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,295 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.validateEntry = validateEntry;
|
|
37
|
+
exports.validateWiki = validateWiki;
|
|
38
|
+
exports.flagEntry = flagEntry;
|
|
39
|
+
exports.deprecateEntry = deprecateEntry;
|
|
40
|
+
exports.adjustConfidence = adjustConfidence;
|
|
41
|
+
exports.markSolutionWorked = markSolutionWorked;
|
|
42
|
+
exports.markSolutionFailed = markSolutionFailed;
|
|
43
|
+
// src/validate.ts
|
|
44
|
+
const fs = __importStar(require("fs"));
|
|
45
|
+
const path = __importStar(require("path"));
|
|
46
|
+
const types_js_1 = require("./types.js");
|
|
47
|
+
const entry_js_1 = require("./entry.js");
|
|
48
|
+
/**
|
|
49
|
+
* Extracts file references from content (backtick paths like `src/file.ts`).
|
|
50
|
+
*
|
|
51
|
+
* @param content - The markdown content to search
|
|
52
|
+
* @returns Array of file paths found in backticks
|
|
53
|
+
*/
|
|
54
|
+
function extractFileReferences(content) {
|
|
55
|
+
// Match backtick-enclosed paths that look like file paths
|
|
56
|
+
// Pattern: `path/to/file.ext` or `./path/to/file.ext` or `../path/to/file.ext`
|
|
57
|
+
const regex = /`((?:\.{0,2}\/)?[\w./-]+\.\w+)`/g;
|
|
58
|
+
const matches = [];
|
|
59
|
+
let match;
|
|
60
|
+
while ((match = regex.exec(content)) !== null) {
|
|
61
|
+
const filePath = match[1];
|
|
62
|
+
// Filter out obvious non-file-paths (URLs, etc.)
|
|
63
|
+
if (!filePath.includes('://') && !filePath.startsWith('http')) {
|
|
64
|
+
matches.push(filePath);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return matches;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Extracts C3 references from content ([[c3-component]]).
|
|
71
|
+
*
|
|
72
|
+
* @param content - The markdown content to search
|
|
73
|
+
* @returns Array of C3 references found
|
|
74
|
+
*/
|
|
75
|
+
function extractC3References(content) {
|
|
76
|
+
// Match [[c3-xxx]] pattern
|
|
77
|
+
const regex = /\[\[(c3-[\w-]+)\]\]/g;
|
|
78
|
+
const matches = [];
|
|
79
|
+
let match;
|
|
80
|
+
while ((match = regex.exec(content)) !== null) {
|
|
81
|
+
matches.push(match[1]);
|
|
82
|
+
}
|
|
83
|
+
return matches;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Checks if a file exists relative to the project root.
|
|
87
|
+
*
|
|
88
|
+
* @param projectRoot - The root directory of the project
|
|
89
|
+
* @param filePath - The file path to check
|
|
90
|
+
* @returns True if the file exists
|
|
91
|
+
*/
|
|
92
|
+
function fileExists(projectRoot, filePath) {
|
|
93
|
+
const fullPath = path.join(projectRoot, filePath);
|
|
94
|
+
return fs.existsSync(fullPath);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Validates a single wiki entry for issues.
|
|
98
|
+
*
|
|
99
|
+
* @param projectRoot - The root directory of the project
|
|
100
|
+
* @param entryPath - Relative path to the entry from the wiki directory
|
|
101
|
+
* @returns Array of validation issues found
|
|
102
|
+
*/
|
|
103
|
+
function validateEntry(projectRoot, entryPath) {
|
|
104
|
+
const entry = (0, entry_js_1.readEntry)(projectRoot, entryPath);
|
|
105
|
+
if (!entry) {
|
|
106
|
+
return [{
|
|
107
|
+
type: 'broken_reference',
|
|
108
|
+
message: `Entry not found: ${entryPath}`,
|
|
109
|
+
entryPath
|
|
110
|
+
}];
|
|
111
|
+
}
|
|
112
|
+
const issues = [];
|
|
113
|
+
// Check for broken file references
|
|
114
|
+
const fileRefs = extractFileReferences(entry.content);
|
|
115
|
+
for (const fileRef of fileRefs) {
|
|
116
|
+
if (!fileExists(projectRoot, fileRef)) {
|
|
117
|
+
issues.push({
|
|
118
|
+
type: 'broken_reference',
|
|
119
|
+
message: `Broken file reference: ${fileRef}`,
|
|
120
|
+
entryPath
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Check for missing C3 references (C3 refs that don't resolve)
|
|
125
|
+
// For now, we just check if the C3 reference format is used but can't be validated
|
|
126
|
+
// This is a placeholder for when C3 integration is implemented
|
|
127
|
+
const c3Refs = extractC3References(entry.content);
|
|
128
|
+
const c3Path = path.join(projectRoot, '.c3');
|
|
129
|
+
if (c3Refs.length > 0 && !fs.existsSync(c3Path)) {
|
|
130
|
+
for (const c3Ref of c3Refs) {
|
|
131
|
+
issues.push({
|
|
132
|
+
type: 'missing_c3',
|
|
133
|
+
message: `C3 reference cannot be validated (no .c3 directory): ${c3Ref}`,
|
|
134
|
+
entryPath
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// Check if entry is flagged
|
|
139
|
+
if (entry.frontmatter.status === 'flagged') {
|
|
140
|
+
issues.push({
|
|
141
|
+
type: 'flagged',
|
|
142
|
+
message: `Entry is flagged for review`,
|
|
143
|
+
entryPath
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
// Check if entry is a stub
|
|
147
|
+
if (entry.frontmatter.stub) {
|
|
148
|
+
issues.push({
|
|
149
|
+
type: 'stub',
|
|
150
|
+
message: `Entry is a stub and needs expansion`,
|
|
151
|
+
entryPath
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
return issues;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Validates the entire wiki and returns a comprehensive report.
|
|
158
|
+
*
|
|
159
|
+
* @param projectRoot - The root directory of the project
|
|
160
|
+
* @returns Validation report with counts and issues
|
|
161
|
+
*/
|
|
162
|
+
async function validateWiki(projectRoot) {
|
|
163
|
+
const entries = await (0, entry_js_1.listEntries)(projectRoot);
|
|
164
|
+
const report = {
|
|
165
|
+
total: entries.length,
|
|
166
|
+
active: 0,
|
|
167
|
+
flagged: 0,
|
|
168
|
+
deprecated: 0,
|
|
169
|
+
issues: []
|
|
170
|
+
};
|
|
171
|
+
for (const entry of entries) {
|
|
172
|
+
// Count by status
|
|
173
|
+
switch (entry.frontmatter.status) {
|
|
174
|
+
case 'active':
|
|
175
|
+
report.active++;
|
|
176
|
+
break;
|
|
177
|
+
case 'flagged':
|
|
178
|
+
report.flagged++;
|
|
179
|
+
break;
|
|
180
|
+
case 'deprecated':
|
|
181
|
+
report.deprecated++;
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
// Validate each entry and collect issues
|
|
185
|
+
const entryIssues = validateEntry(projectRoot, entry.path);
|
|
186
|
+
report.issues.push(...entryIssues);
|
|
187
|
+
}
|
|
188
|
+
return report;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Marks an entry as flagged with the given reason.
|
|
192
|
+
*
|
|
193
|
+
* @param projectRoot - The root directory of the project
|
|
194
|
+
* @param entryPath - Relative path to the entry from the wiki directory
|
|
195
|
+
* @param reason - The reason for flagging the entry
|
|
196
|
+
* @returns The updated WikiEntry
|
|
197
|
+
*/
|
|
198
|
+
function flagEntry(projectRoot, entryPath, reason) {
|
|
199
|
+
return (0, entry_js_1.updateEntry)(projectRoot, entryPath, { status: 'flagged' }, {
|
|
200
|
+
by: 'claude',
|
|
201
|
+
reason,
|
|
202
|
+
context: 'validation'
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Marks an entry as deprecated with the given reason.
|
|
207
|
+
*
|
|
208
|
+
* @param projectRoot - The root directory of the project
|
|
209
|
+
* @param entryPath - Relative path to the entry from the wiki directory
|
|
210
|
+
* @param reason - The reason for deprecating the entry
|
|
211
|
+
* @returns The updated WikiEntry
|
|
212
|
+
*/
|
|
213
|
+
function deprecateEntry(projectRoot, entryPath, reason) {
|
|
214
|
+
return (0, entry_js_1.updateEntry)(projectRoot, entryPath, { status: 'deprecated' }, {
|
|
215
|
+
by: 'claude',
|
|
216
|
+
reason,
|
|
217
|
+
context: 'validation'
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Adjusts the confidence level of an entry up or down.
|
|
222
|
+
* Up: +20 points (capped at 100)
|
|
223
|
+
* Down: -30 points (auto-flag if result < 40)
|
|
224
|
+
*
|
|
225
|
+
* @param projectRoot - The root directory of the project
|
|
226
|
+
* @param entryPath - Relative path to the entry from the wiki directory
|
|
227
|
+
* @param direction - 'up' to increase confidence, 'down' to decrease
|
|
228
|
+
* @returns The updated WikiEntry
|
|
229
|
+
* @throws Error if entry not found
|
|
230
|
+
*/
|
|
231
|
+
function adjustConfidence(projectRoot, entryPath, direction) {
|
|
232
|
+
const entry = (0, entry_js_1.readEntry)(projectRoot, entryPath);
|
|
233
|
+
if (!entry) {
|
|
234
|
+
throw new Error(`Entry not found: ${entryPath}`);
|
|
235
|
+
}
|
|
236
|
+
const currentConfidence = entry.frontmatter.confidence;
|
|
237
|
+
let newConfidence;
|
|
238
|
+
if (direction === 'up') {
|
|
239
|
+
newConfidence = Math.min(currentConfidence + 20, types_js_1.CONFIDENCE.MAX);
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
newConfidence = Math.max(currentConfidence - 30, types_js_1.CONFIDENCE.MIN);
|
|
243
|
+
}
|
|
244
|
+
// Only update if confidence actually changed
|
|
245
|
+
if (newConfidence === currentConfidence) {
|
|
246
|
+
return entry;
|
|
247
|
+
}
|
|
248
|
+
// Auto-flag if confidence drops below threshold
|
|
249
|
+
const shouldFlag = direction === 'down' && newConfidence < types_js_1.CONFIDENCE.THRESHOLD;
|
|
250
|
+
return (0, entry_js_1.updateEntry)(projectRoot, entryPath, {
|
|
251
|
+
confidence: newConfidence,
|
|
252
|
+
...(shouldFlag ? { status: 'flagged' } : {})
|
|
253
|
+
}, {
|
|
254
|
+
by: 'claude',
|
|
255
|
+
context: `confidence adjusted ${direction}`,
|
|
256
|
+
reason: `Confidence changed from ${currentConfidence} to ${newConfidence}${shouldFlag ? ' (auto-flagged: below threshold)' : ''}`
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Marks that a solution from an entry worked, increasing its confidence.
|
|
261
|
+
*
|
|
262
|
+
* @param projectRoot - The root directory of the project
|
|
263
|
+
* @param entryPath - Relative path to the entry from the wiki directory
|
|
264
|
+
* @returns The updated WikiEntry
|
|
265
|
+
*/
|
|
266
|
+
function markSolutionWorked(projectRoot, entryPath) {
|
|
267
|
+
const entry = (0, entry_js_1.readEntry)(projectRoot, entryPath);
|
|
268
|
+
if (!entry) {
|
|
269
|
+
throw new Error(`Entry not found: ${entryPath}`);
|
|
270
|
+
}
|
|
271
|
+
// Increase confidence
|
|
272
|
+
const updatedEntry = adjustConfidence(projectRoot, entryPath, 'up');
|
|
273
|
+
// Add a validated audit entry if confidence changed
|
|
274
|
+
if (updatedEntry.frontmatter.confidence !== entry.frontmatter.confidence) {
|
|
275
|
+
return (0, entry_js_1.updateEntry)(projectRoot, entryPath, {}, {
|
|
276
|
+
by: 'claude',
|
|
277
|
+
context: 'solution-validated',
|
|
278
|
+
reason: 'Solution worked successfully'
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
return updatedEntry;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Marks that a solution from an entry failed, decreasing its confidence.
|
|
285
|
+
* Auto-flags if confidence drops below threshold (handled by adjustConfidence).
|
|
286
|
+
*
|
|
287
|
+
* @param projectRoot - The root directory of the project
|
|
288
|
+
* @param entryPath - Relative path to the entry from the wiki directory
|
|
289
|
+
* @returns The updated WikiEntry
|
|
290
|
+
*/
|
|
291
|
+
function markSolutionFailed(projectRoot, entryPath) {
|
|
292
|
+
// Decrease confidence (auto-flags if below threshold)
|
|
293
|
+
return adjustConfidence(projectRoot, entryPath, 'down');
|
|
294
|
+
}
|
|
295
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/validate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// hooks/error-lookup.ts
|
|
2
|
+
import {
|
|
3
|
+
wikiExists,
|
|
4
|
+
matchTrigger,
|
|
5
|
+
getBestMatch,
|
|
6
|
+
WikiEntry,
|
|
7
|
+
CONFIDENCE,
|
|
8
|
+
ErrorLookupOutput,
|
|
9
|
+
SearchResult,
|
|
10
|
+
validateErrorLookupInput,
|
|
11
|
+
ValidationError,
|
|
12
|
+
ErrorLookupContext
|
|
13
|
+
} from '../src/index.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Extracts the solution section from wiki entry content.
|
|
17
|
+
*/
|
|
18
|
+
function extractSolution(content: string): string {
|
|
19
|
+
// Look for Solution heading
|
|
20
|
+
const solutionMatch = content.match(/## Solution\n([\s\S]*?)(?=\n## |$)/);
|
|
21
|
+
if (solutionMatch) {
|
|
22
|
+
return solutionMatch[1].trim().slice(0, 200) + '...';
|
|
23
|
+
}
|
|
24
|
+
// Fallback: first 200 chars
|
|
25
|
+
return content.slice(0, 200) + '...';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function onErrorLookup(input: unknown): Promise<ErrorLookupOutput | null> {
|
|
29
|
+
try {
|
|
30
|
+
// Validate input first
|
|
31
|
+
const validatedInput = validateErrorLookupInput(input);
|
|
32
|
+
const { projectRoot, errorText, toolResult } = validatedInput;
|
|
33
|
+
|
|
34
|
+
// Get error text from either direct input or tool stderr
|
|
35
|
+
const error = errorText || toolResult?.stderr || '';
|
|
36
|
+
|
|
37
|
+
if (!error || !wikiExists(projectRoot)) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Try to match error against trigger patterns
|
|
42
|
+
const results = await matchTrigger(projectRoot, error);
|
|
43
|
+
const bestMatch = getBestMatch(results);
|
|
44
|
+
|
|
45
|
+
if (bestMatch && bestMatch.entry.frontmatter.confidence >= CONFIDENCE.THRESHOLD) {
|
|
46
|
+
// Record usage for analytics
|
|
47
|
+
try {
|
|
48
|
+
const { recordEntryUsage } = await import('../src/index.js');
|
|
49
|
+
recordEntryUsage(projectRoot, bestMatch.entry.path);
|
|
50
|
+
} catch {
|
|
51
|
+
// Usage tracking failure is non-critical
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Output for Claude Code hook integration (user-facing console logs)
|
|
55
|
+
console.log(`📚 Solvdex found a solution:`);
|
|
56
|
+
console.log(` "${bestMatch.entry.frontmatter.title}"`);
|
|
57
|
+
console.log(` Confidence: ${bestMatch.entry.frontmatter.confidence}`);
|
|
58
|
+
console.log(` `);
|
|
59
|
+
console.log(` Solution: ${extractSolution(bestMatch.entry.content)}`);
|
|
60
|
+
|
|
61
|
+
// Structured output for Claude Code (includes both old and new format for backward compatibility)
|
|
62
|
+
const output: ErrorLookupOutput = {
|
|
63
|
+
// Old format (for backward compatibility)
|
|
64
|
+
type: 'wiki_solution',
|
|
65
|
+
message: `Wiki: Found "${bestMatch.entry.frontmatter.title}" (confidence: ${bestMatch.entry.frontmatter.confidence})`,
|
|
66
|
+
entry: bestMatch.entry,
|
|
67
|
+
// New format (Claude Code integration)
|
|
68
|
+
continue: true,
|
|
69
|
+
hookSpecificOutput: {
|
|
70
|
+
type: 'solution_found',
|
|
71
|
+
message: `Found solution: "${bestMatch.entry.frontmatter.title}"`,
|
|
72
|
+
entries: [{
|
|
73
|
+
title: bestMatch.entry.frontmatter.title,
|
|
74
|
+
category: bestMatch.entry.category,
|
|
75
|
+
path: bestMatch.entry.path,
|
|
76
|
+
confidence: bestMatch.entry.frontmatter.confidence
|
|
77
|
+
}]
|
|
78
|
+
},
|
|
79
|
+
additionalContext: formatSolutionForContext(bestMatch)
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// Output JSON marker + JSON (MUST be last output)
|
|
83
|
+
console.log('\n__HOOK_OUTPUT__');
|
|
84
|
+
console.log(JSON.stringify(output));
|
|
85
|
+
|
|
86
|
+
return output;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return null;
|
|
90
|
+
} catch (error) {
|
|
91
|
+
// Handle validation errors separately
|
|
92
|
+
if (error instanceof ValidationError) {
|
|
93
|
+
console.error(`[Solvdex] Invalid input: ${error.message}`);
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
// Graceful degradation - log error but don't crash
|
|
97
|
+
console.error(`[Solvdex] Error in error-lookup hook: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Formats a solution match into a readable context string for Claude Code.
|
|
104
|
+
*/
|
|
105
|
+
function formatSolutionForContext(match: SearchResult): string {
|
|
106
|
+
const e = match.entry;
|
|
107
|
+
return `## ${e.frontmatter.title} (${e.category})\nConfidence: ${e.frontmatter.confidence}\n\n${e.content}`;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export default onErrorLookup;
|
package/hooks/hooks.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Solvdex wiki hooks for auto-capture and retrieval",
|
|
3
|
+
"hooks": {
|
|
4
|
+
"SessionStart": [
|
|
5
|
+
{
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/session-start.py",
|
|
10
|
+
"timeout": 30
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"UserPromptSubmit": [
|
|
16
|
+
{
|
|
17
|
+
"hooks": [
|
|
18
|
+
{
|
|
19
|
+
"type": "command",
|
|
20
|
+
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/prompt-enrich.py",
|
|
21
|
+
"timeout": 30
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"PostToolUseFailure": [
|
|
27
|
+
{
|
|
28
|
+
"hooks": [
|
|
29
|
+
{
|
|
30
|
+
"type": "command",
|
|
31
|
+
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/error-lookup.py",
|
|
32
|
+
"timeout": 30
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
"Stop": [
|
|
38
|
+
{
|
|
39
|
+
"hooks": [
|
|
40
|
+
{
|
|
41
|
+
"type": "command",
|
|
42
|
+
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/post-task.py",
|
|
43
|
+
"timeout": 30
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
}
|