pikakit 3.0.5 → 3.7.2

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 (100) hide show
  1. package/README.md +1 -1
  2. package/bin/lib/commands/install.js +119 -242
  3. package/package.json +3 -4
  4. package/lib/agent-cli/bin/agent.js +0 -187
  5. package/lib/agent-cli/dashboard/dashboard_server.js +0 -312
  6. package/lib/agent-cli/lib/ab-testing.js +0 -364
  7. package/lib/agent-cli/lib/audit.js +0 -154
  8. package/lib/agent-cli/lib/audit.test.js +0 -100
  9. package/lib/agent-cli/lib/auto-learn.js +0 -319
  10. package/lib/agent-cli/lib/backup.js +0 -138
  11. package/lib/agent-cli/lib/backup.test.js +0 -78
  12. package/lib/agent-cli/lib/causality-engine.js +0 -331
  13. package/lib/agent-cli/lib/cognitive-lesson.js +0 -476
  14. package/lib/agent-cli/lib/completion.js +0 -149
  15. package/lib/agent-cli/lib/config.js +0 -35
  16. package/lib/agent-cli/lib/dashboard-data.js +0 -380
  17. package/lib/agent-cli/lib/eslint-fix.js +0 -238
  18. package/lib/agent-cli/lib/evolution-signal.js +0 -215
  19. package/lib/agent-cli/lib/export.js +0 -86
  20. package/lib/agent-cli/lib/export.test.js +0 -65
  21. package/lib/agent-cli/lib/fix.js +0 -337
  22. package/lib/agent-cli/lib/fix.test.js +0 -80
  23. package/lib/agent-cli/lib/gemini-export.js +0 -83
  24. package/lib/agent-cli/lib/generate-registry.js +0 -42
  25. package/lib/agent-cli/lib/hooks/install-hooks.js +0 -152
  26. package/lib/agent-cli/lib/hooks/lint-learn.js +0 -172
  27. package/lib/agent-cli/lib/icons.js +0 -93
  28. package/lib/agent-cli/lib/ignore.js +0 -116
  29. package/lib/agent-cli/lib/ignore.test.js +0 -58
  30. package/lib/agent-cli/lib/init.js +0 -124
  31. package/lib/agent-cli/lib/knowledge-index.js +0 -326
  32. package/lib/agent-cli/lib/knowledge-metrics.js +0 -335
  33. package/lib/agent-cli/lib/knowledge-retention.js +0 -398
  34. package/lib/agent-cli/lib/knowledge-validator.js +0 -312
  35. package/lib/agent-cli/lib/learn.js +0 -255
  36. package/lib/agent-cli/lib/learn.test.js +0 -70
  37. package/lib/agent-cli/lib/metrics-collector.js +0 -410
  38. package/lib/agent-cli/lib/proposals.js +0 -199
  39. package/lib/agent-cli/lib/proposals.test.js +0 -56
  40. package/lib/agent-cli/lib/recall.js +0 -835
  41. package/lib/agent-cli/lib/recall.test.js +0 -107
  42. package/lib/agent-cli/lib/reinforcement.js +0 -299
  43. package/lib/agent-cli/lib/selfevolution-bridge.js +0 -167
  44. package/lib/agent-cli/lib/settings.js +0 -203
  45. package/lib/agent-cli/lib/skill-generator.js +0 -379
  46. package/lib/agent-cli/lib/skill-learn.js +0 -296
  47. package/lib/agent-cli/lib/stats.js +0 -132
  48. package/lib/agent-cli/lib/stats.test.js +0 -94
  49. package/lib/agent-cli/lib/types.js +0 -33
  50. package/lib/agent-cli/lib/ui/audit-ui.js +0 -146
  51. package/lib/agent-cli/lib/ui/backup-ui.js +0 -107
  52. package/lib/agent-cli/lib/ui/clack-helpers.js +0 -317
  53. package/lib/agent-cli/lib/ui/common.js +0 -83
  54. package/lib/agent-cli/lib/ui/completion-ui.js +0 -126
  55. package/lib/agent-cli/lib/ui/custom-select.js +0 -69
  56. package/lib/agent-cli/lib/ui/dashboard-ui.js +0 -222
  57. package/lib/agent-cli/lib/ui/evolution-signals-ui.js +0 -107
  58. package/lib/agent-cli/lib/ui/export-ui.js +0 -94
  59. package/lib/agent-cli/lib/ui/fix-all-ui.js +0 -191
  60. package/lib/agent-cli/lib/ui/help-ui.js +0 -49
  61. package/lib/agent-cli/lib/ui/index.js +0 -199
  62. package/lib/agent-cli/lib/ui/init-ui.js +0 -56
  63. package/lib/agent-cli/lib/ui/knowledge-ui.js +0 -55
  64. package/lib/agent-cli/lib/ui/learn-ui.js +0 -706
  65. package/lib/agent-cli/lib/ui/lessons-ui.js +0 -148
  66. package/lib/agent-cli/lib/ui/pretty.js +0 -145
  67. package/lib/agent-cli/lib/ui/proposals-ui.js +0 -99
  68. package/lib/agent-cli/lib/ui/recall-ui.js +0 -342
  69. package/lib/agent-cli/lib/ui/routing-demo.js +0 -79
  70. package/lib/agent-cli/lib/ui/routing-ui.js +0 -325
  71. package/lib/agent-cli/lib/ui/settings-ui.js +0 -381
  72. package/lib/agent-cli/lib/ui/stats-ui.js +0 -123
  73. package/lib/agent-cli/lib/ui/watch-ui.js +0 -236
  74. package/lib/agent-cli/lib/watcher.js +0 -181
  75. package/lib/agent-cli/lib/watcher.test.js +0 -85
  76. package/lib/agent-cli/src/MIGRATION.md +0 -418
  77. package/lib/agent-cli/src/README.md +0 -367
  78. package/lib/agent-cli/src/core/evolution/evolution-signal.js +0 -42
  79. package/lib/agent-cli/src/core/evolution/index.js +0 -17
  80. package/lib/agent-cli/src/core/evolution/review-gate.js +0 -40
  81. package/lib/agent-cli/src/core/evolution/signal-detector.js +0 -137
  82. package/lib/agent-cli/src/core/evolution/signal-queue.js +0 -79
  83. package/lib/agent-cli/src/core/evolution/threshold-checker.js +0 -79
  84. package/lib/agent-cli/src/core/index.js +0 -15
  85. package/lib/agent-cli/src/core/learning/cognitive-enhancer.js +0 -282
  86. package/lib/agent-cli/src/core/learning/index.js +0 -12
  87. package/lib/agent-cli/src/core/learning/lesson-synthesizer.js +0 -83
  88. package/lib/agent-cli/src/core/scanning/index.js +0 -14
  89. package/lib/agent-cli/src/data/index.js +0 -13
  90. package/lib/agent-cli/src/data/repositories/index.js +0 -8
  91. package/lib/agent-cli/src/data/repositories/lesson-repository.js +0 -130
  92. package/lib/agent-cli/src/data/repositories/signal-repository.js +0 -119
  93. package/lib/agent-cli/src/data/storage/index.js +0 -8
  94. package/lib/agent-cli/src/data/storage/json-storage.js +0 -64
  95. package/lib/agent-cli/src/data/storage/yaml-storage.js +0 -66
  96. package/lib/agent-cli/src/infrastructure/index.js +0 -13
  97. package/lib/agent-cli/src/presentation/formatters/skill-formatter.js +0 -232
  98. package/lib/agent-cli/src/services/export-service.js +0 -162
  99. package/lib/agent-cli/src/services/index.js +0 -13
  100. package/lib/agent-cli/src/services/learning-service.js +0 -99
@@ -1,116 +0,0 @@
1
- /**
2
- * @fileoverview Ignore patterns parser for PikaKit
3
- * Supports .agentignore file with glob patterns
4
- */
5
-
6
- import fs from "fs";
7
- import path from "path";
8
- import { cwd } from "./config.js";
9
-
10
- /** Default patterns always ignored */
11
- const DEFAULT_IGNORES = [
12
- "node_modules/**",
13
- ".git/**",
14
- "dist/**",
15
- "build/**",
16
- ".next/**",
17
- "coverage/**",
18
- "*.log"
19
- ];
20
-
21
- /**
22
- * Load ignore patterns from .agentignore file
23
- * @param {string} basePath - Base directory
24
- * @returns {string[]} Array of patterns
25
- */
26
- export function loadIgnorePatterns(basePath = cwd) {
27
- const patterns = [...DEFAULT_IGNORES];
28
- const ignoreFile = path.join(basePath, ".agentignore");
29
-
30
- try {
31
- if (fs.existsSync(ignoreFile)) {
32
- const content = fs.readFileSync(ignoreFile, "utf8");
33
- const lines = content.split("\n");
34
-
35
- for (const line of lines) {
36
- const trimmed = line.trim();
37
- // Skip empty lines and comments
38
- if (trimmed && !trimmed.startsWith("#")) {
39
- patterns.push(trimmed);
40
- }
41
- }
42
- }
43
- } catch (e) {
44
- // Silently use defaults
45
- }
46
-
47
- return [...new Set(patterns)]; // Remove duplicates
48
- }
49
-
50
- /**
51
- * Check if a file path matches any ignore pattern
52
- * @param {string} filePath - Relative file path
53
- * @param {string[]} patterns - Ignore patterns
54
- * @returns {boolean}
55
- */
56
- export function isIgnored(filePath, patterns) {
57
- const normalized = filePath.replace(/\\/g, "/");
58
-
59
- for (const pattern of patterns) {
60
- // Simple glob matching
61
- const regex = patternToRegex(pattern);
62
- if (regex.test(normalized)) {
63
- return true;
64
- }
65
- }
66
-
67
- return false;
68
- }
69
-
70
- /**
71
- * Convert glob pattern to regex
72
- * @param {string} pattern - Glob pattern
73
- * @returns {RegExp}
74
- */
75
- function patternToRegex(pattern) {
76
- let regex = pattern
77
- .replace(/\./g, "\\.") // Escape dots
78
- .replace(/\*\*/g, ".*") // ** matches everything
79
- .replace(/\*/g, "[^/]*") // * matches segment
80
- .replace(/\?/g, "."); // ? matches single char
81
-
82
- // Handle directory patterns (ending with /)
83
- if (pattern.endsWith("/")) {
84
- regex = regex.slice(0, -1) + "(/.*)?";
85
- }
86
-
87
- return new RegExp(`^${regex}$|/${regex}$|^${regex}/`);
88
- }
89
-
90
- /**
91
- * Filter files array by ignore patterns
92
- * @param {string[]} files - Array of file paths
93
- * @param {string[]} patterns - Ignore patterns
94
- * @returns {{ included: string[], ignored: number }}
95
- */
96
- export function filterFiles(files, patterns) {
97
- const included = [];
98
- let ignored = 0;
99
-
100
- for (const file of files) {
101
- if (isIgnored(file, patterns)) {
102
- ignored++;
103
- } else {
104
- included.push(file);
105
- }
106
- }
107
-
108
- return { included, ignored };
109
- }
110
-
111
- export default {
112
- loadIgnorePatterns,
113
- isIgnored,
114
- filterFiles,
115
- DEFAULT_IGNORES
116
- };
@@ -1,58 +0,0 @@
1
- /**
2
- * @fileoverview Tests for ignore module
3
- */
4
-
5
- import { describe, it, expect, beforeEach, afterEach } from "vitest";
6
- import fs from "fs";
7
- import path from "path";
8
- import os from "os";
9
-
10
- // Import directly without mocking - test actual behavior
11
- import { loadIgnorePatterns, isIgnored } from "./ignore.js";
12
-
13
- describe("ignore", () => {
14
- describe("isIgnored", () => {
15
- it("returns false when no patterns", () => {
16
- const result = isIgnored("some/path.js", []);
17
- expect(result).toBe(false);
18
- });
19
-
20
- it("matches exact pattern", () => {
21
- const result = isIgnored("node_modules/pkg/file.js", ["node_modules"]);
22
- expect(result).toBe(true);
23
- });
24
-
25
- it("matches glob pattern", () => {
26
- const result = isIgnored("debug.log", ["*.log"]);
27
- expect(result).toBe(true);
28
- });
29
-
30
- it("returns false for non-matching path", () => {
31
- const result = isIgnored("src/app.js", ["*.log", "node_modules"]);
32
- expect(result).toBe(false);
33
- });
34
-
35
- it("matches directory pattern", () => {
36
- const result = isIgnored("dist/bundle.js", ["dist/**"]);
37
- expect(result).toBe(true);
38
- });
39
-
40
- it("matches nested paths", () => {
41
- const result = isIgnored(".git/objects/pack", [".git/**"]);
42
- expect(result).toBe(true);
43
- });
44
- });
45
-
46
- describe("loadIgnorePatterns", () => {
47
- it("returns array of patterns", () => {
48
- const patterns = loadIgnorePatterns();
49
- expect(Array.isArray(patterns)).toBe(true);
50
- });
51
-
52
- it("includes default patterns", () => {
53
- const patterns = loadIgnorePatterns();
54
- // Should have at least some patterns (defaults or from file)
55
- expect(patterns.length).toBeGreaterThan(0);
56
- });
57
- });
58
- });
@@ -1,124 +0,0 @@
1
- /**
2
- * @fileoverview Project initialization wizard
3
- * Sets up agent config for new projects
4
- */
5
-
6
- import fs from "fs";
7
- import path from "path";
8
- import { cwd, AGENT_DIR, KNOWLEDGE_DIR, LESSONS_PATH } from "./config.js";
9
-
10
- /**
11
- * Detect project type based on files
12
- * @returns {string} Project type
13
- */
14
- export function detectProjectType() {
15
- const files = fs.readdirSync(cwd);
16
-
17
- if (files.includes("package.json")) {
18
- const pkg = JSON.parse(fs.readFileSync(path.join(cwd, "package.json"), "utf8"));
19
-
20
- if (pkg.dependencies?.next || pkg.devDependencies?.next) return "nextjs";
21
- if (pkg.dependencies?.react || pkg.devDependencies?.react) return "react";
22
- if (pkg.dependencies?.vue || pkg.devDependencies?.vue) return "vue";
23
- if (pkg.dependencies?.express || pkg.devDependencies?.express) return "node";
24
- return "node";
25
- }
26
-
27
- if (files.includes("requirements.txt") || files.includes("pyproject.toml")) return "python";
28
- if (files.includes("Cargo.toml")) return "rust";
29
- if (files.includes("go.mod")) return "go";
30
- if (files.includes("pom.xml") || files.includes("build.gradle")) return "java";
31
-
32
- return "generic";
33
- }
34
-
35
- /**
36
- * Get default ignore patterns for project type
37
- * @param {string} projectType
38
- * @returns {string[]}
39
- */
40
- export function getDefaultIgnorePatterns(projectType) {
41
- const common = [
42
- "node_modules/**",
43
- ".git/**",
44
- "dist/**",
45
- "build/**",
46
- "coverage/**",
47
- "*.log",
48
- "*.lock",
49
- ".env*"
50
- ];
51
-
52
- const specific = {
53
- node: ["package-lock.json"],
54
- nextjs: [".next/**", "out/**"],
55
- react: ["build/**"],
56
- vue: [".nuxt/**"],
57
- python: ["__pycache__/**", "*.pyc", ".venv/**", "venv/**"],
58
- rust: ["target/**"],
59
- go: ["vendor/**"],
60
- java: ["target/**", "*.class"],
61
- generic: []
62
- };
63
-
64
- return [...common, ...(specific[projectType] || [])];
65
- }
66
-
67
- /**
68
- * Initialize agent config
69
- * @param {object} options
70
- * @param {boolean} options.force - Overwrite existing
71
- * @returns {{ success: boolean, message: string }}
72
- */
73
- export function initProject(options = {}) {
74
- const { force = false } = options;
75
-
76
- // Check if already initialized
77
- if (fs.existsSync(KNOWLEDGE_DIR) && !force) {
78
- return {
79
- success: false,
80
- message: "Already initialized. Use --force to reinitialize."
81
- };
82
- }
83
-
84
- // Detect project type
85
- const projectType = detectProjectType();
86
-
87
- // Create directories
88
- fs.mkdirSync(KNOWLEDGE_DIR, { recursive: true });
89
-
90
- // Create lessons-learned.yaml
91
- if (!fs.existsSync(LESSONS_PATH)) {
92
- const initialLessons = `# PikaKit - Lessons Learned
93
- # Project Type: ${projectType}
94
- # Created: ${new Date().toISOString()}
95
-
96
- lessons: []
97
- `;
98
- fs.writeFileSync(LESSONS_PATH, initialLessons);
99
- }
100
-
101
- // Create .agentignore if not exists
102
- const agentignorePath = path.join(cwd, ".agentignore");
103
- if (!fs.existsSync(agentignorePath)) {
104
- const patterns = getDefaultIgnorePatterns(projectType);
105
- fs.writeFileSync(agentignorePath, patterns.join("\n") + "\n");
106
- }
107
-
108
- return {
109
- success: true,
110
- message: `Initialized for ${projectType} project`,
111
- projectType,
112
- paths: {
113
- knowledge: KNOWLEDGE_DIR,
114
- lessons: LESSONS_PATH,
115
- agentignore: agentignorePath
116
- }
117
- };
118
- }
119
-
120
- export default {
121
- detectProjectType,
122
- getDefaultIgnorePatterns,
123
- initProject
124
- };
@@ -1,326 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Knowledge Index Generator
4
- *
5
- * Builds inverted index for O(1) pattern lookup in knowledge base.
6
- * Regenerates on-demand when knowledge files change.
7
- *
8
- * Usage:
9
- * agent index --rebuild # Force rebuild index
10
- * agent index --status # Check index freshness
11
- */
12
-
13
- import fs from 'fs';
14
- import path from 'path';
15
- import yaml from 'js-yaml';
16
- import { KNOWLEDGE_DIR } from './config.js';
17
-
18
- const INDEX_PATH = path.join(KNOWLEDGE_DIR, 'index.json');
19
- const INDEX_VERSION = 1;
20
-
21
- /**
22
- * Load all lessons from knowledge base
23
- * @returns {{ mistakes: Array, improvements: Array }}
24
- */
25
- function loadAllLessons() {
26
- const mistakes = [];
27
- const improvements = [];
28
-
29
- // Load mistakes.yaml
30
- const mistakesPath = path.join(KNOWLEDGE_DIR, 'mistakes.yaml');
31
- if (fs.existsSync(mistakesPath)) {
32
- const data = yaml.load(fs.readFileSync(mistakesPath, 'utf8'));
33
- if (data?.mistakes) {
34
- mistakes.push(...data.mistakes.map(m => ({ ...m, type: 'mistake' })));
35
- }
36
- }
37
-
38
- // Load improvements.yaml
39
- const improvementsPath = path.join(KNOWLEDGE_DIR, 'improvements.yaml');
40
- if (fs.existsSync(improvementsPath)) {
41
- const data = yaml.load(fs.readFileSync(improvementsPath, 'utf8'));
42
- if (data?.improvements) {
43
- improvements.push(...data.improvements.map(i => ({ ...i, type: 'improvement' })));
44
- }
45
- }
46
-
47
- return { mistakes, improvements };
48
- }
49
-
50
- /**
51
- * Build inverted index from lessons
52
- * @param {Array} lessons - All lessons combined
53
- * @returns {Object} Index structure
54
- */
55
- function buildIndex(lessons) {
56
- const patternIndex = {}; // pattern word -> lesson IDs
57
- const tagIndex = {}; // tag -> lesson IDs
58
- const idIndex = {}; // id -> lesson (for direct lookup)
59
- const severityIndex = { // severity -> lesson IDs
60
- ERROR: [],
61
- WARNING: [],
62
- INFO: []
63
- };
64
-
65
- for (const lesson of lessons) {
66
- const id = lesson.id;
67
-
68
- // ID index (direct lookup)
69
- idIndex[id] = {
70
- pattern: lesson.pattern,
71
- message: lesson.message,
72
- severity: lesson.severity || 'WARNING',
73
- type: lesson.type,
74
- hitCount: lesson.hitCount || 0,
75
- confidence: lesson.cognitive?.confidence || 0.3
76
- };
77
-
78
- // Pattern index (tokenize pattern for partial matching)
79
- if (lesson.pattern) {
80
- const tokens = tokenizePattern(lesson.pattern);
81
- for (const token of tokens) {
82
- if (!patternIndex[token]) {
83
- patternIndex[token] = [];
84
- }
85
- if (!patternIndex[token].includes(id)) {
86
- patternIndex[token].push(id);
87
- }
88
- }
89
- }
90
-
91
- // Tag index
92
- if (lesson.tags && Array.isArray(lesson.tags)) {
93
- for (const tag of lesson.tags) {
94
- if (!tagIndex[tag]) {
95
- tagIndex[tag] = [];
96
- }
97
- if (!tagIndex[tag].includes(id)) {
98
- tagIndex[tag].push(id);
99
- }
100
- }
101
- }
102
-
103
- // Severity index
104
- const severity = lesson.severity || 'WARNING';
105
- if (severityIndex[severity]) {
106
- severityIndex[severity].push(id);
107
- }
108
- }
109
-
110
- return {
111
- version: INDEX_VERSION,
112
- generatedAt: new Date().toISOString(),
113
- stats: {
114
- totalLessons: lessons.length,
115
- totalMistakes: lessons.filter(l => l.type === 'mistake').length,
116
- totalImprovements: lessons.filter(l => l.type === 'improvement').length,
117
- totalPatterns: Object.keys(patternIndex).length,
118
- totalTags: Object.keys(tagIndex).length
119
- },
120
- patternIndex,
121
- tagIndex,
122
- severityIndex,
123
- idIndex
124
- };
125
- }
126
-
127
- /**
128
- * Tokenize a regex pattern into searchable words
129
- * @param {string} pattern - Regex pattern
130
- * @returns {string[]} Tokens
131
- */
132
- function tokenizePattern(pattern) {
133
- // Extract alphanumeric words, ignoring regex special chars
134
- const words = pattern
135
- .replace(/[\[\]\(\)\{\}\.\*\+\?\^\$\\|]/g, ' ')
136
- .split(/\s+/)
137
- .map(w => w.toLowerCase().trim())
138
- .filter(w => w.length >= 2);
139
-
140
- return [...new Set(words)];
141
- }
142
-
143
- /**
144
- * Get modification time of knowledge files
145
- * @returns {number} Most recent mtime
146
- */
147
- function getKnowledgeMtime() {
148
- const files = ['mistakes.yaml', 'improvements.yaml', 'lessons-learned.yaml'];
149
- let maxMtime = 0;
150
-
151
- for (const file of files) {
152
- const filepath = path.join(KNOWLEDGE_DIR, file);
153
- if (fs.existsSync(filepath)) {
154
- const stat = fs.statSync(filepath);
155
- if (stat.mtime.getTime() > maxMtime) {
156
- maxMtime = stat.mtime.getTime();
157
- }
158
- }
159
- }
160
-
161
- return maxMtime;
162
- }
163
-
164
- /**
165
- * Check if index is stale
166
- * @returns {{ stale: boolean, reason?: string }}
167
- */
168
- export function checkIndexFreshness() {
169
- if (!fs.existsSync(INDEX_PATH)) {
170
- return { stale: true, reason: 'Index does not exist' };
171
- }
172
-
173
- try {
174
- const index = JSON.parse(fs.readFileSync(INDEX_PATH, 'utf8'));
175
- const indexTime = new Date(index.generatedAt).getTime();
176
- const knowledgeTime = getKnowledgeMtime();
177
-
178
- if (knowledgeTime > indexTime) {
179
- return { stale: true, reason: 'Knowledge files modified after index' };
180
- }
181
-
182
- if (index.version !== INDEX_VERSION) {
183
- return { stale: true, reason: `Index version mismatch (${index.version} vs ${INDEX_VERSION})` };
184
- }
185
-
186
- return { stale: false };
187
- } catch (e) {
188
- return { stale: true, reason: `Index corrupted: ${e.message}` };
189
- }
190
- }
191
-
192
- /**
193
- * Load or rebuild index
194
- * @param {boolean} forceRebuild - Force rebuild even if fresh
195
- * @returns {Object} Index
196
- */
197
- export function loadIndex(forceRebuild = false) {
198
- const freshness = checkIndexFreshness();
199
-
200
- if (!forceRebuild && !freshness.stale) {
201
- // Load existing index
202
- return JSON.parse(fs.readFileSync(INDEX_PATH, 'utf8'));
203
- }
204
-
205
- // Rebuild index
206
- return rebuildIndex();
207
- }
208
-
209
- /**
210
- * Force rebuild index
211
- * @returns {Object} New index
212
- */
213
- export function rebuildIndex() {
214
- const { mistakes, improvements } = loadAllLessons();
215
- const allLessons = [...mistakes, ...improvements];
216
-
217
- const index = buildIndex(allLessons);
218
-
219
- // Save index
220
- fs.mkdirSync(KNOWLEDGE_DIR, { recursive: true });
221
- fs.writeFileSync(INDEX_PATH, JSON.stringify(index, null, 2), 'utf8');
222
-
223
- return index;
224
- }
225
-
226
- /**
227
- * Search index by pattern
228
- * @param {string} query - Search query
229
- * @param {Object} index - Loaded index
230
- * @returns {string[]} Matching lesson IDs
231
- */
232
- export function searchByPattern(query, index) {
233
- const tokens = tokenizePattern(query);
234
- const matchingIds = new Set();
235
-
236
- for (const token of tokens) {
237
- if (index.patternIndex[token]) {
238
- for (const id of index.patternIndex[token]) {
239
- matchingIds.add(id);
240
- }
241
- }
242
- }
243
-
244
- return [...matchingIds];
245
- }
246
-
247
- /**
248
- * Search index by tag
249
- * @param {string} tag - Tag to search
250
- * @param {Object} index - Loaded index
251
- * @returns {string[]} Matching lesson IDs
252
- */
253
- export function searchByTag(tag, index) {
254
- return index.tagIndex[tag] || [];
255
- }
256
-
257
- /**
258
- * Get lesson by ID
259
- * @param {string} id - Lesson ID
260
- * @param {Object} index - Loaded index
261
- * @returns {Object|null} Lesson info
262
- */
263
- export function getById(id, index) {
264
- return index.idIndex[id] || null;
265
- }
266
-
267
- /**
268
- * CLI entry point
269
- */
270
- function main() {
271
- const args = process.argv.slice(2);
272
-
273
- if (args.includes('--status')) {
274
- const freshness = checkIndexFreshness();
275
- if (freshness.stale) {
276
- console.log(`⚠️ Index is STALE: ${freshness.reason}`);
277
- process.exit(1);
278
- } else {
279
- const index = loadIndex();
280
- console.log(`✅ Index is FRESH`);
281
- console.log(` Generated: ${index.generatedAt}`);
282
- console.log(` Lessons: ${index.stats.totalLessons}`);
283
- console.log(` Patterns: ${index.stats.totalPatterns}`);
284
- console.log(` Tags: ${index.stats.totalTags}`);
285
- }
286
- return;
287
- }
288
-
289
- if (args.includes('--rebuild')) {
290
- console.log('🔄 Rebuilding knowledge index...');
291
- const index = rebuildIndex();
292
- console.log(`✅ Index rebuilt successfully`);
293
- console.log(` Lessons: ${index.stats.totalLessons}`);
294
- console.log(` Patterns: ${index.stats.totalPatterns}`);
295
- console.log(` Tags: ${index.stats.totalTags}`);
296
- return;
297
- }
298
-
299
- console.log(`
300
- 📇 Knowledge Index Manager
301
-
302
- Usage:
303
- agent index --rebuild Rebuild index from knowledge files
304
- agent index --status Check if index is fresh or stale
305
-
306
- The index provides O(1) lookup for:
307
- - Pattern matching (by keyword)
308
- - Tag filtering
309
- - Severity grouping
310
- - Direct ID lookup
311
- `);
312
- }
313
-
314
- // Run if called directly
315
- if (process.argv[1]?.includes('knowledge-index')) {
316
- main();
317
- }
318
-
319
- export default {
320
- loadIndex,
321
- rebuildIndex,
322
- checkIndexFreshness,
323
- searchByPattern,
324
- searchByTag,
325
- getById
326
- };