ruvnet-kb-first 5.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 (52) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +674 -0
  3. package/SKILL.md +740 -0
  4. package/bin/kb-first.js +123 -0
  5. package/install/init-project.sh +435 -0
  6. package/install/install-global.sh +257 -0
  7. package/install/kb-first-autodetect.sh +108 -0
  8. package/install/kb-first-command.md +80 -0
  9. package/install/kb-first-skill.md +262 -0
  10. package/package.json +87 -0
  11. package/phases/00-assessment.md +529 -0
  12. package/phases/01-storage.md +194 -0
  13. package/phases/01.5-hooks-setup.md +521 -0
  14. package/phases/02-kb-creation.md +413 -0
  15. package/phases/03-persistence.md +125 -0
  16. package/phases/04-visualization.md +170 -0
  17. package/phases/05-integration.md +114 -0
  18. package/phases/06-scaffold.md +130 -0
  19. package/phases/07-build.md +493 -0
  20. package/phases/08-verification.md +597 -0
  21. package/phases/09-security.md +512 -0
  22. package/phases/10-documentation.md +613 -0
  23. package/phases/11-deployment.md +670 -0
  24. package/phases/testing.md +713 -0
  25. package/scripts/1.5-hooks-verify.sh +252 -0
  26. package/scripts/8.1-code-scan.sh +58 -0
  27. package/scripts/8.2-import-check.sh +42 -0
  28. package/scripts/8.3-source-returns.sh +52 -0
  29. package/scripts/8.4-startup-verify.sh +65 -0
  30. package/scripts/8.5-fallback-check.sh +63 -0
  31. package/scripts/8.6-attribution.sh +56 -0
  32. package/scripts/8.7-confidence.sh +56 -0
  33. package/scripts/8.8-gap-logging.sh +70 -0
  34. package/scripts/9-security-audit.sh +202 -0
  35. package/scripts/init-project.sh +395 -0
  36. package/scripts/verify-enforcement.sh +167 -0
  37. package/src/commands/hooks.js +361 -0
  38. package/src/commands/init.js +315 -0
  39. package/src/commands/phase.js +372 -0
  40. package/src/commands/score.js +380 -0
  41. package/src/commands/status.js +193 -0
  42. package/src/commands/verify.js +286 -0
  43. package/src/index.js +56 -0
  44. package/src/mcp-server.js +412 -0
  45. package/templates/attention-router.ts +534 -0
  46. package/templates/code-analysis.ts +683 -0
  47. package/templates/federated-kb-learner.ts +649 -0
  48. package/templates/gnn-engine.ts +1091 -0
  49. package/templates/intentions.md +277 -0
  50. package/templates/kb-client.ts +905 -0
  51. package/templates/schema.sql +303 -0
  52. package/templates/sona-config.ts +312 -0
@@ -0,0 +1,167 @@
1
+ #!/bin/bash
2
+ # KB-First Final Verification Script
3
+ # Run this to verify all KB enforcement rules are followed
4
+
5
+ set -e
6
+
7
+ echo "=== KB-First v3.0 Verification ==="
8
+ echo ""
9
+
10
+ errors=0
11
+ warnings=0
12
+
13
+ # Color codes
14
+ RED='\033[0;31m'
15
+ GREEN='\033[0;32m'
16
+ YELLOW='\033[1;33m'
17
+ NC='\033[0m' # No Color
18
+
19
+ pass() {
20
+ echo -e " ${GREEN}✅${NC} $1"
21
+ }
22
+
23
+ fail() {
24
+ echo -e " ${RED}❌${NC} $1"
25
+ errors=$((errors + 1))
26
+ }
27
+
28
+ warn() {
29
+ echo -e " ${YELLOW}⚠️${NC} $1"
30
+ warnings=$((warnings + 1))
31
+ }
32
+
33
+ # ============================================
34
+ # Rule 1: No Hardcoded Domain Logic
35
+ # ============================================
36
+ echo "Rule 1: No hardcoded domain logic..."
37
+
38
+ if [ -d "src/domain" ]; then
39
+ # Check for hardcoded decimals (likely rates/percentages)
40
+ hardcoded=$(grep -rnE "= 0\.[0-9]+" src/domain/ 2>/dev/null | grep -v "confidence" | grep -v "test" || true)
41
+ if [ -n "$hardcoded" ]; then
42
+ fail "Found potential hardcoded decimals:"
43
+ echo "$hardcoded" | head -5
44
+ else
45
+ pass "No hardcoded decimals found"
46
+ fi
47
+
48
+ # Check for DEFAULT_ constants
49
+ defaults=$(grep -rn "DEFAULT_" src/domain/ 2>/dev/null || true)
50
+ if [ -n "$defaults" ]; then
51
+ fail "Found DEFAULT_ constants:"
52
+ echo "$defaults" | head -5
53
+ else
54
+ pass "No DEFAULT_ constants found"
55
+ fi
56
+ else
57
+ warn "src/domain/ directory not found"
58
+ fi
59
+
60
+ # ============================================
61
+ # Rule 2: All Domain Files Import KB
62
+ # ============================================
63
+ echo ""
64
+ echo "Rule 2: All domain files import from kb/..."
65
+
66
+ if [ -d "src/domain" ]; then
67
+ for file in src/domain/*.ts; do
68
+ if [ -f "$file" ]; then
69
+ if ! grep -q "from.*kb" "$file"; then
70
+ fail "$file does not import from kb/"
71
+ fi
72
+ fi
73
+ done
74
+
75
+ if [ $errors -eq 0 ]; then
76
+ pass "All domain files import from kb/"
77
+ fi
78
+ else
79
+ warn "src/domain/ directory not found"
80
+ fi
81
+
82
+ # ============================================
83
+ # Rule 3: Responses Include kbSources
84
+ # ============================================
85
+ echo ""
86
+ echo "Rule 3: Responses include kbSources..."
87
+
88
+ if [ -d "src/domain" ]; then
89
+ missing_sources=$(grep -rL "kbSources" src/domain/*.ts 2>/dev/null || true)
90
+ if [ -n "$missing_sources" ]; then
91
+ warn "Files may not return kbSources:"
92
+ echo "$missing_sources"
93
+ else
94
+ pass "kbSources found in domain files"
95
+ fi
96
+ else
97
+ warn "src/domain/ directory not found"
98
+ fi
99
+
100
+ # ============================================
101
+ # Rule 4: Startup Verification
102
+ # ============================================
103
+ echo ""
104
+ echo "Rule 4: Startup verification..."
105
+
106
+ if [ -f "src/index.ts" ]; then
107
+ if grep -q "verifyConnection" src/index.ts; then
108
+ pass "Entry point calls verifyConnection"
109
+ else
110
+ fail "Entry point does not verify KB connection"
111
+ fi
112
+
113
+ if grep -q "process.exit" src/index.ts; then
114
+ pass "Entry point exits on failure"
115
+ else
116
+ fail "Entry point does not exit on KB failure"
117
+ fi
118
+ else
119
+ warn "src/index.ts not found"
120
+ fi
121
+
122
+ # ============================================
123
+ # Rule 5: No Fallback Logic
124
+ # ============================================
125
+ echo ""
126
+ echo "Rule 5: No fallback logic..."
127
+
128
+ if [ -d "src/domain" ]; then
129
+ fallbacks=$(grep -rnE "\|\| DEFAULT|\|\| \[|\|\| \{\}" src/domain/ 2>/dev/null || true)
130
+ if [ -n "$fallbacks" ]; then
131
+ fail "Found fallback patterns:"
132
+ echo "$fallbacks" | head -5
133
+ else
134
+ pass "No fallback patterns found"
135
+ fi
136
+ else
137
+ warn "src/domain/ directory not found"
138
+ fi
139
+
140
+ # ============================================
141
+ # KB_ENFORCEMENT.md Check
142
+ # ============================================
143
+ echo ""
144
+ echo "KB Enforcement document..."
145
+
146
+ if [ -f "KB_ENFORCEMENT.md" ]; then
147
+ pass "KB_ENFORCEMENT.md present"
148
+ else
149
+ warn "KB_ENFORCEMENT.md not found in project root"
150
+ fi
151
+
152
+ # ============================================
153
+ # Summary
154
+ # ============================================
155
+ echo ""
156
+ echo "=== Summary ==="
157
+
158
+ if [ $errors -eq 0 ] && [ $warnings -eq 0 ]; then
159
+ echo -e "${GREEN}All checks passed!${NC}"
160
+ exit 0
161
+ elif [ $errors -eq 0 ]; then
162
+ echo -e "${YELLOW}$warnings warning(s), no errors${NC}"
163
+ exit 0
164
+ else
165
+ echo -e "${RED}$errors error(s), $warnings warning(s)${NC}"
166
+ exit 1
167
+ fi
@@ -0,0 +1,361 @@
1
+ /**
2
+ * KB-First Hooks Command
3
+ *
4
+ * Manages KB-First hooks for enforcement.
5
+ */
6
+
7
+ import chalk from 'chalk';
8
+ import ora from 'ora';
9
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, chmodSync } from 'fs';
10
+ import { join } from 'path';
11
+
12
+ const HOOK_TEMPLATES = {
13
+ 'pre-tool-use.py': `#!/usr/bin/env python3
14
+ """
15
+ KB-First PreToolUse Hook
16
+ Intercepts Write operations to enforce KB-First patterns.
17
+ """
18
+
19
+ import json
20
+ import sys
21
+ import os
22
+
23
+ def check_kb_first(tool_input):
24
+ """Check if Write operation follows KB-First principles."""
25
+ if tool_input.get('tool_name') != 'Write':
26
+ return {'decision': 'approve'}
27
+
28
+ file_path = tool_input.get('tool_input', {}).get('file_path', '')
29
+ content = tool_input.get('tool_input', {}).get('content', '')
30
+
31
+ # Check if it's a code file
32
+ code_extensions = ['.ts', '.tsx', '.js', '.jsx', '.py', '.go', '.rs', '.java']
33
+ is_code_file = any(file_path.endswith(ext) for ext in code_extensions)
34
+
35
+ if not is_code_file:
36
+ return {'decision': 'approve'}
37
+
38
+ # Check for KB citation header
39
+ has_kb_citation = 'KB-Generated:' in content or 'Sources:' in content
40
+
41
+ if not has_kb_citation:
42
+ return {
43
+ 'decision': 'block',
44
+ 'message': 'KB-First Violation: Code files must include KB citation header. Use kb_code_gen first.'
45
+ }
46
+
47
+ return {'decision': 'approve'}
48
+
49
+ if __name__ == '__main__':
50
+ try:
51
+ input_data = json.loads(sys.stdin.read())
52
+ result = check_kb_first(input_data)
53
+ print(json.dumps(result))
54
+ except Exception as e:
55
+ print(json.dumps({'decision': 'approve', 'error': str(e)}))
56
+ `,
57
+
58
+ 'post-tool-use.py': `#!/usr/bin/env python3
59
+ """
60
+ KB-First PostToolUse Hook
61
+ Tracks KB usage and logs gaps.
62
+ """
63
+
64
+ import json
65
+ import sys
66
+ import os
67
+ from datetime import datetime
68
+
69
+ def track_kb_usage(tool_result):
70
+ """Track KB search results and log gaps."""
71
+ tool_name = tool_result.get('tool_name', '')
72
+
73
+ # Track KB searches
74
+ if 'kb_search' in tool_name or 'kb_code_gen' in tool_name:
75
+ result = tool_result.get('tool_result', {})
76
+ coverage = result.get('kb_coverage', 'unknown')
77
+
78
+ if coverage == 'gap':
79
+ log_gap(tool_result)
80
+
81
+ return {'status': 'ok'}
82
+
83
+ def log_gap(tool_result):
84
+ """Log KB gap for future improvement."""
85
+ gap_log = os.path.join(os.getcwd(), '.ruvector', 'gaps.jsonl')
86
+
87
+ # Ensure directory exists
88
+ os.makedirs(os.path.dirname(gap_log), exist_ok=True)
89
+
90
+ gap_entry = {
91
+ 'timestamp': datetime.now().isoformat(),
92
+ 'query': tool_result.get('tool_input', {}).get('query', ''),
93
+ 'description': tool_result.get('tool_input', {}).get('description', ''),
94
+ 'file_path': tool_result.get('tool_input', {}).get('file_path', '')
95
+ }
96
+
97
+ with open(gap_log, 'a') as f:
98
+ f.write(json.dumps(gap_entry) + '\\n')
99
+
100
+ if __name__ == '__main__':
101
+ try:
102
+ input_data = json.loads(sys.stdin.read())
103
+ result = track_kb_usage(input_data)
104
+ print(json.dumps(result))
105
+ except Exception as e:
106
+ print(json.dumps({'status': 'error', 'error': str(e)}))
107
+ `,
108
+
109
+ 'session-end.py': `#!/usr/bin/env python3
110
+ """
111
+ KB-First SessionEnd Hook
112
+ Generates session summary and updates metrics.
113
+ """
114
+
115
+ import json
116
+ import sys
117
+ import os
118
+ from datetime import datetime
119
+
120
+ def session_summary(session_data):
121
+ """Generate KB-First session summary."""
122
+ cwd = os.getcwd()
123
+ summary_file = os.path.join(cwd, '.ruvector', 'sessions.jsonl')
124
+
125
+ # Ensure directory exists
126
+ os.makedirs(os.path.dirname(summary_file), exist_ok=True)
127
+
128
+ # Count KB operations
129
+ kb_searches = session_data.get('kb_searches', 0)
130
+ kb_writes = session_data.get('kb_writes', 0)
131
+ gaps_logged = session_data.get('gaps_logged', 0)
132
+
133
+ summary = {
134
+ 'timestamp': datetime.now().isoformat(),
135
+ 'duration_minutes': session_data.get('duration_minutes', 0),
136
+ 'kb_searches': kb_searches,
137
+ 'kb_writes': kb_writes,
138
+ 'gaps_logged': gaps_logged,
139
+ 'files_modified': session_data.get('files_modified', [])
140
+ }
141
+
142
+ with open(summary_file, 'a') as f:
143
+ f.write(json.dumps(summary) + '\\n')
144
+
145
+ return {'status': 'ok', 'summary': summary}
146
+
147
+ if __name__ == '__main__':
148
+ try:
149
+ input_data = json.loads(sys.stdin.read())
150
+ result = session_summary(input_data)
151
+ print(json.dumps(result))
152
+ except Exception as e:
153
+ print(json.dumps({'status': 'error', 'error': str(e)}))
154
+ `
155
+ };
156
+
157
+ export async function hooksCommand(options) {
158
+ const cwd = process.cwd();
159
+
160
+ console.log('');
161
+ console.log(chalk.cyan('KB-First Hooks Manager'));
162
+ console.log('');
163
+
164
+ if (options.install) {
165
+ await installHooks(cwd);
166
+ } else if (options.verify) {
167
+ await verifyHooks(cwd);
168
+ } else if (options.train) {
169
+ await trainHooks(cwd);
170
+ } else if (options.status) {
171
+ await showHookStatus(cwd);
172
+ } else {
173
+ // Default: show status
174
+ await showHookStatus(cwd);
175
+ }
176
+ }
177
+
178
+ async function installHooks(cwd) {
179
+ const spinner = ora('Installing KB-First hooks...').start();
180
+
181
+ const hooksDir = join(cwd, '.ruvector', 'hooks');
182
+
183
+ // Create hooks directory
184
+ if (!existsSync(hooksDir)) {
185
+ mkdirSync(hooksDir, { recursive: true });
186
+ }
187
+
188
+ // Write hook files
189
+ for (const [filename, content] of Object.entries(HOOK_TEMPLATES)) {
190
+ const hookPath = join(hooksDir, filename);
191
+ writeFileSync(hookPath, content);
192
+ chmodSync(hookPath, 0o755);
193
+ }
194
+
195
+ // Update config
196
+ const configPath = join(cwd, '.ruvector', 'config.json');
197
+ if (existsSync(configPath)) {
198
+ const config = JSON.parse(readFileSync(configPath, 'utf-8'));
199
+ config.hooks = {
200
+ enabled: true,
201
+ preToolUse: true,
202
+ postToolUse: true,
203
+ sessionEnd: true,
204
+ installedAt: new Date().toISOString()
205
+ };
206
+ writeFileSync(configPath, JSON.stringify(config, null, 2));
207
+ }
208
+
209
+ spinner.succeed('Hooks installed successfully');
210
+
211
+ console.log('');
212
+ console.log(chalk.white('Installed hooks:'));
213
+ console.log(chalk.gray(' - pre-tool-use.py (KB citation enforcement)'));
214
+ console.log(chalk.gray(' - post-tool-use.py (Gap logging)'));
215
+ console.log(chalk.gray(' - session-end.py (Session summary)'));
216
+ console.log('');
217
+ console.log(chalk.yellow('Note: Add hooks to Claude Code settings.json:'));
218
+ console.log(chalk.gray(`
219
+ "hooks": {
220
+ "PreToolUse": [
221
+ {
222
+ "matcher": "Write",
223
+ "hooks": [".ruvector/hooks/pre-tool-use.py"]
224
+ }
225
+ ],
226
+ "PostToolUse": [".ruvector/hooks/post-tool-use.py"],
227
+ "SessionEnd": [".ruvector/hooks/session-end.py"]
228
+ }
229
+ `));
230
+ }
231
+
232
+ async function verifyHooks(cwd) {
233
+ console.log(chalk.white('Verifying hooks installation...'));
234
+ console.log('');
235
+
236
+ const hooksDir = join(cwd, '.ruvector', 'hooks');
237
+ const requiredHooks = ['pre-tool-use.py', 'post-tool-use.py', 'session-end.py'];
238
+
239
+ let passed = 0;
240
+ let failed = 0;
241
+
242
+ for (const hook of requiredHooks) {
243
+ const hookPath = join(hooksDir, hook);
244
+
245
+ if (existsSync(hookPath)) {
246
+ // Check if executable
247
+ try {
248
+ const { statSync } = await import('fs');
249
+ const stats = statSync(hookPath);
250
+ const isExecutable = (stats.mode & 0o111) !== 0;
251
+
252
+ if (isExecutable) {
253
+ console.log(chalk.green(` ✅ ${hook}`));
254
+ passed++;
255
+ } else {
256
+ console.log(chalk.yellow(` ⚠️ ${hook} (not executable)`));
257
+ failed++;
258
+ }
259
+ } catch {
260
+ console.log(chalk.red(` ❌ ${hook} (error checking)`));
261
+ failed++;
262
+ }
263
+ } else {
264
+ console.log(chalk.red(` ❌ ${hook} (not found)`));
265
+ failed++;
266
+ }
267
+ }
268
+
269
+ console.log('');
270
+ if (failed === 0) {
271
+ console.log(chalk.green('All hooks verified successfully.'));
272
+ } else {
273
+ console.log(chalk.yellow(`${failed} hook(s) need attention.`));
274
+ console.log(chalk.gray('Run: kb-first hooks --install'));
275
+ }
276
+ }
277
+
278
+ async function trainHooks(cwd) {
279
+ const spinner = ora('Pre-training hooks with KB-First patterns...').start();
280
+
281
+ // Create training data for ReasoningBank
282
+ const trainingPatterns = [
283
+ {
284
+ pattern: 'KB citation required for code files',
285
+ trigger: 'Write to .ts, .tsx, .js, .jsx, .py files',
286
+ action: 'Check for KB-Generated: or Sources: header',
287
+ consequence: 'Block if missing KB citation'
288
+ },
289
+ {
290
+ pattern: 'Gap logging on KB search',
291
+ trigger: 'kb_search or kb_code_gen returns coverage=gap',
292
+ action: 'Log to .ruvector/gaps.jsonl',
293
+ consequence: 'Track for future KB improvement'
294
+ },
295
+ {
296
+ pattern: 'Session summary on end',
297
+ trigger: 'Session ends',
298
+ action: 'Write summary to .ruvector/sessions.jsonl',
299
+ consequence: 'Track KB usage metrics'
300
+ }
301
+ ];
302
+
303
+ const patternsPath = join(cwd, '.ruvector', 'training-patterns.json');
304
+ writeFileSync(patternsPath, JSON.stringify(trainingPatterns, null, 2));
305
+
306
+ spinner.succeed('Hooks pre-trained with KB-First patterns');
307
+
308
+ console.log('');
309
+ console.log(chalk.white('Training patterns installed:'));
310
+ for (const pattern of trainingPatterns) {
311
+ console.log(chalk.gray(` - ${pattern.pattern}`));
312
+ }
313
+ }
314
+
315
+ async function showHookStatus(cwd) {
316
+ const configPath = join(cwd, '.ruvector', 'config.json');
317
+ const hooksDir = join(cwd, '.ruvector', 'hooks');
318
+
319
+ if (!existsSync(configPath)) {
320
+ console.log(chalk.red('Not a KB-First project.'));
321
+ console.log(chalk.gray('Run: kb-first init'));
322
+ return;
323
+ }
324
+
325
+ const config = JSON.parse(readFileSync(configPath, 'utf-8'));
326
+ const hooksConfig = config.hooks || {};
327
+
328
+ console.log(chalk.white('Hook Status:'));
329
+ console.log('');
330
+ console.log(` Enabled: ${hooksConfig.enabled ? chalk.green('Yes') : chalk.red('No')}`);
331
+ console.log(` PreToolUse: ${hooksConfig.preToolUse ? chalk.green('Active') : chalk.gray('Inactive')}`);
332
+ console.log(` PostToolUse: ${hooksConfig.postToolUse ? chalk.green('Active') : chalk.gray('Inactive')}`);
333
+ console.log(` SessionEnd: ${hooksConfig.sessionEnd ? chalk.green('Active') : chalk.gray('Inactive')}`);
334
+
335
+ if (hooksConfig.installedAt) {
336
+ console.log(` Installed: ${chalk.gray(hooksConfig.installedAt)}`);
337
+ }
338
+
339
+ console.log('');
340
+
341
+ // Check files
342
+ const hookFiles = ['pre-tool-use.py', 'post-tool-use.py', 'session-end.py'];
343
+ const foundHooks = hookFiles.filter(f => existsSync(join(hooksDir, f)));
344
+
345
+ console.log(chalk.white('Hook Files:'));
346
+ console.log(` ${foundHooks.length}/${hookFiles.length} hooks installed`);
347
+
348
+ // Show gaps count if any
349
+ const gapsPath = join(cwd, '.ruvector', 'gaps.jsonl');
350
+ if (existsSync(gapsPath)) {
351
+ const gapsContent = readFileSync(gapsPath, 'utf-8').trim();
352
+ const gapCount = gapsContent ? gapsContent.split('\n').length : 0;
353
+ console.log(` ${chalk.yellow(gapCount)} KB gaps logged`);
354
+ }
355
+
356
+ console.log('');
357
+ console.log(chalk.gray('Commands:'));
358
+ console.log(chalk.gray(' kb-first hooks --install Install hooks'));
359
+ console.log(chalk.gray(' kb-first hooks --verify Verify installation'));
360
+ console.log(chalk.gray(' kb-first hooks --train Pre-train with patterns'));
361
+ }