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,159 @@
|
|
|
1
|
+
// hooks/session-start.ts
|
|
2
|
+
import {
|
|
3
|
+
wikiExists,
|
|
4
|
+
searchWiki,
|
|
5
|
+
DEFAULT_CATEGORIES,
|
|
6
|
+
SessionStartOutput,
|
|
7
|
+
SearchResult,
|
|
8
|
+
validateSessionStartInput,
|
|
9
|
+
ValidationError,
|
|
10
|
+
SessionStartContext
|
|
11
|
+
} from '../src/index.js';
|
|
12
|
+
|
|
13
|
+
const CATEGORY_KEYWORDS: Record<string, string[]> = {
|
|
14
|
+
issues: ['error', 'fix', 'bug', 'broken', 'fails', 'crash', 'exception', 'trouble'],
|
|
15
|
+
patterns: ['pattern', 'template', 'reusable', 'design', 'approach', 'best practice'],
|
|
16
|
+
gotchas: ['careful', 'watch out', 'pitfall', 'gotcha', 'trap', 'avoid', 'never'],
|
|
17
|
+
testing: ['test', 'mock', 'fixture', 'assert', 'spec', 'coverage', 'jest', 'vitest'],
|
|
18
|
+
docs: ['document', 'readme', 'guide', 'tutorial', 'api docs', 'documentation'],
|
|
19
|
+
security: ['auth', 'token', 'vulnerability', 'permission', 'csrf', 'xss', 'injection', 'security'],
|
|
20
|
+
performance: ['slow', 'optimize', 'memory', 'latency', 'benchmark', 'profiling', 'performance']
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const CATEGORY_PATH_HINTS: Record<string, string[]> = {
|
|
24
|
+
testing: ['test', 'spec', 'fixture', 'mock', '__tests__'],
|
|
25
|
+
docs: ['doc', 'readme', 'wiki', 'guide', 'docs'],
|
|
26
|
+
security: ['auth', 'secret', 'cred', 'permission', 'security'],
|
|
27
|
+
performance: ['perf', 'bench', 'profile', 'optim']
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
function detectCategoryFromPaths(paths: string[]): string[] {
|
|
31
|
+
const detected: Set<string> = new Set();
|
|
32
|
+
|
|
33
|
+
for (const filePath of paths) {
|
|
34
|
+
const pathLower = filePath.toLowerCase();
|
|
35
|
+
for (const [category, hints] of Object.entries(CATEGORY_PATH_HINTS)) {
|
|
36
|
+
if (hints.some(hint => pathLower.includes(hint))) {
|
|
37
|
+
detected.add(category);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return Array.from(detected);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export async function onSessionStart(context: unknown): Promise<SessionStartOutput | null> {
|
|
46
|
+
try {
|
|
47
|
+
// Validate input first
|
|
48
|
+
const validatedContext = validateSessionStartInput(context);
|
|
49
|
+
const { projectRoot, taskDescription, filePaths } = validatedContext;
|
|
50
|
+
|
|
51
|
+
if (!wikiExists(projectRoot)) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!taskDescription) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Check which categories might be relevant based on keywords
|
|
60
|
+
const relevantCategories: string[] = [];
|
|
61
|
+
for (const category of DEFAULT_CATEGORIES) {
|
|
62
|
+
if (isRelevantCategory(taskDescription, category)) {
|
|
63
|
+
relevantCategories.push(category);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Also check paths for category hints
|
|
68
|
+
if (filePaths && filePaths.length > 0) {
|
|
69
|
+
const pathCategories = detectCategoryFromPaths(filePaths);
|
|
70
|
+
for (const cat of pathCategories) {
|
|
71
|
+
if (!relevantCategories.includes(cat)) {
|
|
72
|
+
relevantCategories.push(cat);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Search wiki for relevant entries
|
|
78
|
+
const searchResults = await searchWiki(projectRoot, { query: taskDescription });
|
|
79
|
+
|
|
80
|
+
if (searchResults.length > 0 || relevantCategories.length > 0) {
|
|
81
|
+
const entries = searchResults.map(r => ({
|
|
82
|
+
title: r.entry.frontmatter.title,
|
|
83
|
+
category: r.entry.category,
|
|
84
|
+
path: r.entry.path
|
|
85
|
+
}));
|
|
86
|
+
|
|
87
|
+
const categories = relevantCategories.length > 0
|
|
88
|
+
? relevantCategories
|
|
89
|
+
: [...new Set(searchResults.map(r => r.entry.category))];
|
|
90
|
+
|
|
91
|
+
// Output for Claude Code hook integration (user-facing console logs)
|
|
92
|
+
if (searchResults.length > 0) {
|
|
93
|
+
console.log(`\u{1F4DA} Solvdex: Found ${searchResults.length} relevant entries`);
|
|
94
|
+
for (const r of searchResults.slice(0, 3)) {
|
|
95
|
+
console.log(` - ${r.entry.frontmatter.title} (${r.entry.category})`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Structured output for Claude Code (includes both old and new format for backward compatibility)
|
|
100
|
+
const output: SessionStartOutput = {
|
|
101
|
+
// Old format (for backward compatibility)
|
|
102
|
+
type: 'wiki_context',
|
|
103
|
+
message: searchResults.length > 0
|
|
104
|
+
? `Wiki: Found ${searchResults.length} relevant entries`
|
|
105
|
+
: `Wiki: Check ${categories.join(', ')} for related knowledge`,
|
|
106
|
+
categories,
|
|
107
|
+
entries: entries.length > 0 ? entries : undefined,
|
|
108
|
+
// New format (Claude Code integration)
|
|
109
|
+
continue: true,
|
|
110
|
+
hookSpecificOutput: {
|
|
111
|
+
type: 'wiki_context',
|
|
112
|
+
message: searchResults.length > 0
|
|
113
|
+
? `Found ${searchResults.length} wiki entries`
|
|
114
|
+
: `Relevant categories: ${categories.join(', ')}`,
|
|
115
|
+
categories,
|
|
116
|
+
entries: entries.length > 0 ? entries.slice(0, 3) : undefined
|
|
117
|
+
},
|
|
118
|
+
additionalContext: searchResults.length > 0
|
|
119
|
+
? formatEntriesForContext(searchResults.slice(0, 3))
|
|
120
|
+
: undefined
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// Output JSON marker + JSON (MUST be last output)
|
|
124
|
+
console.log('\n__HOOK_OUTPUT__');
|
|
125
|
+
console.log(JSON.stringify(output));
|
|
126
|
+
|
|
127
|
+
return output;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return null;
|
|
131
|
+
} catch (error) {
|
|
132
|
+
// Handle validation errors separately
|
|
133
|
+
if (error instanceof ValidationError) {
|
|
134
|
+
console.error(`[Solvdex] Invalid input: ${error.message}`);
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
// Graceful degradation - log error but don't crash
|
|
138
|
+
console.error(`[Solvdex] Error in session-start hook: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function isRelevantCategory(task: string, category: string): boolean {
|
|
144
|
+
const categoryKeywords = CATEGORY_KEYWORDS[category] || [];
|
|
145
|
+
const taskLower = task.toLowerCase();
|
|
146
|
+
return categoryKeywords.some(kw => taskLower.includes(kw));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Formats search results into a readable context string for Claude Code.
|
|
151
|
+
*/
|
|
152
|
+
function formatEntriesForContext(results: SearchResult[]): string {
|
|
153
|
+
return results.map(r => {
|
|
154
|
+
const e = r.entry;
|
|
155
|
+
return `## ${e.frontmatter.title} (${e.category})\nConfidence: ${e.frontmatter.confidence}\n\n${e.content.substring(0, 300)}...`;
|
|
156
|
+
}).join('\n\n');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export default onSessionStart;
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "solvdex",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Knowledge management system for Claude Code - auto-captures and retrieves project solutions",
|
|
5
|
+
"main": "dist/src/index.js",
|
|
6
|
+
"types": "dist/src/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist/",
|
|
9
|
+
"skills/",
|
|
10
|
+
"hooks/",
|
|
11
|
+
"scripts/",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"keywords": ["claude-code", "wiki", "knowledge-base", "documentation"],
|
|
15
|
+
"author": "duc.do",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc",
|
|
19
|
+
"test": "vitest",
|
|
20
|
+
"test:watch": "vitest watch",
|
|
21
|
+
"lint": "eslint src/",
|
|
22
|
+
"prepublishOnly": "npm run build"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"gray-matter": "^4.0.3",
|
|
26
|
+
"glob": "^10.3.10",
|
|
27
|
+
"yaml": "^2.3.4"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/node": "^20.10.0",
|
|
31
|
+
"typescript": "^5.3.0",
|
|
32
|
+
"vitest": "^1.0.0",
|
|
33
|
+
"eslint": "^8.55.0",
|
|
34
|
+
"@typescript-eslint/eslint-plugin": "^6.13.0",
|
|
35
|
+
"@typescript-eslint/parser": "^6.13.0"
|
|
36
|
+
},
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=18.0.0"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Solvdex PostToolUseFailure hook - looks up solutions for errors
|
|
4
|
+
"""
|
|
5
|
+
import json
|
|
6
|
+
import sys
|
|
7
|
+
import subprocess
|
|
8
|
+
import os
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
def main():
|
|
12
|
+
try:
|
|
13
|
+
# Read input from stdin
|
|
14
|
+
input_data = json.load(sys.stdin)
|
|
15
|
+
except json.JSONDecodeError as e:
|
|
16
|
+
print(f"Error parsing input: {e}", file=sys.stderr)
|
|
17
|
+
sys.exit(1)
|
|
18
|
+
|
|
19
|
+
# Extract context
|
|
20
|
+
project_root = input_data.get("cwd", os.getcwd())
|
|
21
|
+
error_message = input_data.get("errorMessage", "")
|
|
22
|
+
tool_name = input_data.get("toolName", "")
|
|
23
|
+
|
|
24
|
+
# Call Node.js hook implementation
|
|
25
|
+
plugin_root = Path(__file__).parent.parent
|
|
26
|
+
hook_script = plugin_root / "dist" / "hooks" / "error-lookup.js"
|
|
27
|
+
|
|
28
|
+
if not hook_script.exists():
|
|
29
|
+
# Silent fail if not built yet
|
|
30
|
+
sys.exit(0)
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
# Prepare context for TypeScript hook
|
|
34
|
+
context = {
|
|
35
|
+
"projectRoot": project_root,
|
|
36
|
+
"errorMessage": error_message,
|
|
37
|
+
"toolName": tool_name
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# Call the compiled TypeScript hook
|
|
41
|
+
result = subprocess.run(
|
|
42
|
+
["node", str(hook_script)],
|
|
43
|
+
input=json.dumps(context),
|
|
44
|
+
capture_output=True,
|
|
45
|
+
text=True,
|
|
46
|
+
timeout=30
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# Output result to stdout (will be shown to user)
|
|
50
|
+
if result.stdout:
|
|
51
|
+
print(result.stdout, end='')
|
|
52
|
+
|
|
53
|
+
# Exit with same code
|
|
54
|
+
sys.exit(result.returncode)
|
|
55
|
+
|
|
56
|
+
except subprocess.TimeoutExpired:
|
|
57
|
+
print("Hook timed out", file=sys.stderr)
|
|
58
|
+
sys.exit(1)
|
|
59
|
+
except Exception as e:
|
|
60
|
+
print(f"Error executing hook: {e}", file=sys.stderr)
|
|
61
|
+
sys.exit(1)
|
|
62
|
+
|
|
63
|
+
if __name__ == "__main__":
|
|
64
|
+
main()
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Solvdex Stop hook - offers to capture knowledge after task completion
|
|
4
|
+
"""
|
|
5
|
+
import json
|
|
6
|
+
import sys
|
|
7
|
+
import subprocess
|
|
8
|
+
import os
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
def main():
|
|
12
|
+
try:
|
|
13
|
+
# Read input from stdin
|
|
14
|
+
input_data = json.load(sys.stdin)
|
|
15
|
+
except json.JSONDecodeError as e:
|
|
16
|
+
print(f"Error parsing input: {e}", file=sys.stderr)
|
|
17
|
+
sys.exit(1)
|
|
18
|
+
|
|
19
|
+
# Extract context
|
|
20
|
+
project_root = input_data.get("cwd", os.getcwd())
|
|
21
|
+
|
|
22
|
+
# Call Node.js hook implementation
|
|
23
|
+
plugin_root = Path(__file__).parent.parent
|
|
24
|
+
hook_script = plugin_root / "dist" / "hooks" / "post-task.js"
|
|
25
|
+
|
|
26
|
+
if not hook_script.exists():
|
|
27
|
+
# Silent fail if not built yet
|
|
28
|
+
sys.exit(0)
|
|
29
|
+
|
|
30
|
+
try:
|
|
31
|
+
# Prepare context for TypeScript hook
|
|
32
|
+
context = {
|
|
33
|
+
"projectRoot": project_root
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
# Call the compiled TypeScript hook
|
|
37
|
+
result = subprocess.run(
|
|
38
|
+
["node", str(hook_script)],
|
|
39
|
+
input=json.dumps(context),
|
|
40
|
+
capture_output=True,
|
|
41
|
+
text=True,
|
|
42
|
+
timeout=30
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
# Output result to stdout (will be shown to user)
|
|
46
|
+
if result.stdout:
|
|
47
|
+
print(result.stdout, end='')
|
|
48
|
+
|
|
49
|
+
# Exit with same code
|
|
50
|
+
sys.exit(result.returncode)
|
|
51
|
+
|
|
52
|
+
except subprocess.TimeoutExpired:
|
|
53
|
+
print("Hook timed out", file=sys.stderr)
|
|
54
|
+
sys.exit(1)
|
|
55
|
+
except Exception as e:
|
|
56
|
+
print(f"Error executing hook: {e}", file=sys.stderr)
|
|
57
|
+
sys.exit(1)
|
|
58
|
+
|
|
59
|
+
if __name__ == "__main__":
|
|
60
|
+
main()
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Solvdex UserPromptSubmit hook - enriches prompts with relevant wiki context
|
|
4
|
+
"""
|
|
5
|
+
import json
|
|
6
|
+
import sys
|
|
7
|
+
import subprocess
|
|
8
|
+
import os
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
def main():
|
|
12
|
+
try:
|
|
13
|
+
# Read input from stdin
|
|
14
|
+
input_data = json.load(sys.stdin)
|
|
15
|
+
except json.JSONDecodeError as e:
|
|
16
|
+
print(f"Error parsing input: {e}", file=sys.stderr)
|
|
17
|
+
sys.exit(1)
|
|
18
|
+
|
|
19
|
+
# Extract context
|
|
20
|
+
project_root = input_data.get("cwd", os.getcwd())
|
|
21
|
+
prompt = input_data.get("prompt", "")
|
|
22
|
+
file_paths = input_data.get("filePaths", [])
|
|
23
|
+
|
|
24
|
+
# Call Node.js hook implementation
|
|
25
|
+
plugin_root = Path(__file__).parent.parent
|
|
26
|
+
hook_script = plugin_root / "dist" / "hooks" / "prompt-enrich.js"
|
|
27
|
+
|
|
28
|
+
if not hook_script.exists():
|
|
29
|
+
# Silent fail if not built yet
|
|
30
|
+
sys.exit(0)
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
# Prepare context for TypeScript hook
|
|
34
|
+
context = {
|
|
35
|
+
"projectRoot": project_root,
|
|
36
|
+
"prompt": prompt,
|
|
37
|
+
"filePaths": file_paths
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# Call the compiled TypeScript hook
|
|
41
|
+
result = subprocess.run(
|
|
42
|
+
["node", str(hook_script)],
|
|
43
|
+
input=json.dumps(context),
|
|
44
|
+
capture_output=True,
|
|
45
|
+
text=True,
|
|
46
|
+
timeout=30
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# Output result to stdout (will be shown to user)
|
|
50
|
+
if result.stdout:
|
|
51
|
+
print(result.stdout, end='')
|
|
52
|
+
|
|
53
|
+
# Exit with same code
|
|
54
|
+
sys.exit(result.returncode)
|
|
55
|
+
|
|
56
|
+
except subprocess.TimeoutExpired:
|
|
57
|
+
print("Hook timed out", file=sys.stderr)
|
|
58
|
+
sys.exit(1)
|
|
59
|
+
except Exception as e:
|
|
60
|
+
print(f"Error executing hook: {e}", file=sys.stderr)
|
|
61
|
+
sys.exit(1)
|
|
62
|
+
|
|
63
|
+
if __name__ == "__main__":
|
|
64
|
+
main()
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Solvdex SessionStart hook - surfaces relevant wiki entries at session start
|
|
4
|
+
"""
|
|
5
|
+
import json
|
|
6
|
+
import sys
|
|
7
|
+
import subprocess
|
|
8
|
+
import os
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
def main():
|
|
12
|
+
try:
|
|
13
|
+
# Read input from stdin
|
|
14
|
+
input_data = json.load(sys.stdin)
|
|
15
|
+
except json.JSONDecodeError as e:
|
|
16
|
+
print(f"Error parsing input: {e}", file=sys.stderr)
|
|
17
|
+
sys.exit(1)
|
|
18
|
+
|
|
19
|
+
# Extract context
|
|
20
|
+
project_root = input_data.get("cwd", os.getcwd())
|
|
21
|
+
task_description = input_data.get("taskDescription", "")
|
|
22
|
+
file_paths = input_data.get("filePaths", [])
|
|
23
|
+
|
|
24
|
+
# Call Node.js hook implementation
|
|
25
|
+
plugin_root = Path(__file__).parent.parent
|
|
26
|
+
hook_script = plugin_root / "dist" / "hooks" / "session-start.js"
|
|
27
|
+
|
|
28
|
+
if not hook_script.exists():
|
|
29
|
+
# Silent fail if not built yet
|
|
30
|
+
sys.exit(0)
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
# Prepare context for TypeScript hook
|
|
34
|
+
context = {
|
|
35
|
+
"projectRoot": project_root,
|
|
36
|
+
"taskDescription": task_description,
|
|
37
|
+
"filePaths": file_paths
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# Call the compiled TypeScript hook
|
|
41
|
+
result = subprocess.run(
|
|
42
|
+
["node", str(hook_script)],
|
|
43
|
+
input=json.dumps(context),
|
|
44
|
+
capture_output=True,
|
|
45
|
+
text=True,
|
|
46
|
+
timeout=30
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# Output result to stdout (will be shown to user)
|
|
50
|
+
if result.stdout:
|
|
51
|
+
print(result.stdout, end='')
|
|
52
|
+
|
|
53
|
+
# Exit with same code
|
|
54
|
+
sys.exit(result.returncode)
|
|
55
|
+
|
|
56
|
+
except subprocess.TimeoutExpired:
|
|
57
|
+
print("Hook timed out", file=sys.stderr)
|
|
58
|
+
sys.exit(1)
|
|
59
|
+
except Exception as e:
|
|
60
|
+
print(f"Error executing hook: {e}", file=sys.stderr)
|
|
61
|
+
sys.exit(1)
|
|
62
|
+
|
|
63
|
+
if __name__ == "__main__":
|
|
64
|
+
main()
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wiki
|
|
3
|
+
description: Project knowledge wiki - stores and retrieves solutions, patterns, and gotchas across 7 development domains. Use when managing project knowledge, searching for solutions, or capturing learnings.
|
|
4
|
+
user-invocable: true
|
|
5
|
+
disable-model-invocation: false
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Solvdex
|
|
9
|
+
|
|
10
|
+
Project knowledge management with 7 specialized categories for capturing solutions, patterns, and learnings.
|
|
11
|
+
|
|
12
|
+
## Commands
|
|
13
|
+
|
|
14
|
+
| Command | Description |
|
|
15
|
+
|---------|-------------|
|
|
16
|
+
| `/wiki init` | Create `.wiki/` structure |
|
|
17
|
+
| `/wiki add` | Save current solution |
|
|
18
|
+
| `/wiki search <query>` | Full-text search |
|
|
19
|
+
| `/wiki browse` | List entries |
|
|
20
|
+
| `/wiki status` | Show basic stats |
|
|
21
|
+
| `/wiki stats` | Detailed analytics with usage tracking |
|
|
22
|
+
| `/wiki validate` | Check for issues |
|
|
23
|
+
| `/wiki scan` | Generate stubs from project |
|
|
24
|
+
| `/wiki flag <entry>` | Mark needs review |
|
|
25
|
+
| `/wiki fix <entry>` | Update flagged entry |
|
|
26
|
+
| `/wiki export [file]` | Export wiki to JSON |
|
|
27
|
+
| `/wiki import <file>` | Import from export file |
|
|
28
|
+
| `/wiki test-trigger <pattern> <text>` | Test trigger patterns |
|
|
29
|
+
|
|
30
|
+
## Agents
|
|
31
|
+
|
|
32
|
+
| Command | Description |
|
|
33
|
+
|---------|-------------|
|
|
34
|
+
| `/wiki explore <query>` | Deep search agent - finds relevant knowledge across all categories |
|
|
35
|
+
| `/wiki capture` | Capture agent - extracts knowledge from conversation and creates entries |
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
1. Initialize: `/wiki init`
|
|
40
|
+
2. Scan project: `/wiki scan`
|
|
41
|
+
3. Search: `/wiki search timeout error`
|
|
42
|
+
|
|
43
|
+
## Categories
|
|
44
|
+
|
|
45
|
+
| Category | Purpose |
|
|
46
|
+
|----------|---------|
|
|
47
|
+
| `issues/` | Bug fixes, error solutions |
|
|
48
|
+
| `patterns/` | Reusable code patterns |
|
|
49
|
+
| `gotchas/` | Pitfalls, traps |
|
|
50
|
+
| `testing/` | Test strategies, mocks |
|
|
51
|
+
| `docs/` | Documentation templates |
|
|
52
|
+
| `security/` | Auth, vulnerabilities |
|
|
53
|
+
| `performance/` | Optimizations, profiling |
|
|
54
|
+
|
|
55
|
+
## Confidence (0-100)
|
|
56
|
+
|
|
57
|
+
- **80+** - Verified, used multiple times
|
|
58
|
+
- **50-79** - Worked once or partially verified
|
|
59
|
+
- **20-49** - Stub or unverified
|
|
60
|
+
|
|
61
|
+
Run `/wiki status` to see wiki health.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wiki-add
|
|
3
|
+
description: Add current solution or knowledge to the Solvdex wiki. Analyzes conversation context and creates a structured entry.
|
|
4
|
+
argument-hint: [--category=<cat>]
|
|
5
|
+
user-invocable: true
|
|
6
|
+
disable-model-invocation: true
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Add Solvdex Entry
|
|
10
|
+
|
|
11
|
+
Capture current solution or knowledge as a wiki entry.
|
|
12
|
+
|
|
13
|
+
## Process
|
|
14
|
+
|
|
15
|
+
1. Analyze recent conversation context
|
|
16
|
+
2. Determine category (or use provided)
|
|
17
|
+
3. Extract:
|
|
18
|
+
- Problem/situation
|
|
19
|
+
- Solution/decision
|
|
20
|
+
- Related files
|
|
21
|
+
- Tags
|
|
22
|
+
4. Generate entry using category template
|
|
23
|
+
5. Save to `.wiki/<category>/`
|
|
24
|
+
6. Show confirmation
|
|
25
|
+
|
|
26
|
+
## Categories
|
|
27
|
+
|
|
28
|
+
| Category | Use For |
|
|
29
|
+
|----------|---------|
|
|
30
|
+
| issues | Bug fixes, error solutions |
|
|
31
|
+
| patterns | Reusable code patterns |
|
|
32
|
+
| gotchas | Pitfalls, traps |
|
|
33
|
+
| testing | Test strategies, mocks |
|
|
34
|
+
| docs | Documentation templates |
|
|
35
|
+
| security | Auth, vulnerabilities |
|
|
36
|
+
| performance | Optimizations, profiling |
|
|
37
|
+
|
|
38
|
+
## Implementation
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import { createEntry, wikiExists, getTemplate, CONFIDENCE } from 'solvdex';
|
|
42
|
+
|
|
43
|
+
const projectRoot = process.cwd();
|
|
44
|
+
|
|
45
|
+
if (!wikiExists(projectRoot)) {
|
|
46
|
+
console.log('No wiki found. Run `/wiki init` first.');
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Analyze conversation context to extract:
|
|
51
|
+
// - What problem was solved
|
|
52
|
+
// - What solution was applied
|
|
53
|
+
// - What files were involved
|
|
54
|
+
// - Relevant tags
|
|
55
|
+
|
|
56
|
+
const analysis = analyzeConversationContext();
|
|
57
|
+
|
|
58
|
+
const category = args.category || analysis.suggestedCategory;
|
|
59
|
+
const template = getTemplate(category);
|
|
60
|
+
|
|
61
|
+
const entry = createEntry(projectRoot, {
|
|
62
|
+
category,
|
|
63
|
+
title: analysis.title,
|
|
64
|
+
tags: analysis.tags,
|
|
65
|
+
content: {
|
|
66
|
+
[template[0].heading]: analysis.problem,
|
|
67
|
+
[template[1].heading]: analysis.cause || analysis.context,
|
|
68
|
+
[template[2].heading]: analysis.solution,
|
|
69
|
+
},
|
|
70
|
+
trigger: analysis.errorPattern,
|
|
71
|
+
confidence: CONFIDENCE.MEDIUM, // 50 - needs verification
|
|
72
|
+
autoCapture: false
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
console.log(`Wiki: Saved "${entry.frontmatter.title}" to ${category}/`);
|
|
76
|
+
console.log('');
|
|
77
|
+
console.log(`Path: ${entry.path}`);
|
|
78
|
+
console.log(`Tags: ${entry.frontmatter.tags.join(', ')}`);
|
|
79
|
+
console.log(`Confidence: ${entry.frontmatter.confidence}`);
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Output
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
Wiki: Saved "Drizzle Enum Migration Fix" to issues/
|
|
86
|
+
|
|
87
|
+
Path: issues/drizzle-enum-migration-fix.md
|
|
88
|
+
Tags: drizzle, database, migration, enum
|
|
89
|
+
Confidence: 50
|
|
90
|
+
```
|