add-skill-kit 3.2.3 ā 3.2.5
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/README.md +1 -1
- package/bin/lib/commands/help.js +0 -4
- package/bin/lib/commands/install.js +90 -9
- package/bin/lib/ui.js +1 -1
- package/lib/agent-cli/__tests__/adaptive_engine.test.js +190 -0
- package/lib/agent-cli/__tests__/integration/cross_script.test.js +222 -0
- package/lib/agent-cli/__tests__/integration/full_cycle.test.js +230 -0
- package/lib/agent-cli/__tests__/pattern_analyzer.test.js +173 -0
- package/lib/agent-cli/__tests__/pre_execution_check.test.js +167 -0
- package/lib/agent-cli/__tests__/skill_injector.test.js +191 -0
- package/lib/agent-cli/bin/agent.js +191 -0
- package/lib/agent-cli/dashboard/dashboard_server.js +340 -0
- package/lib/agent-cli/dashboard/index.html +538 -0
- package/lib/agent-cli/lib/audit.js +154 -0
- package/lib/agent-cli/lib/audit.test.js +100 -0
- package/lib/agent-cli/lib/auto-learn.js +319 -0
- package/lib/agent-cli/lib/auto_preview.py +148 -0
- package/lib/agent-cli/lib/backup.js +138 -0
- package/lib/agent-cli/lib/backup.test.js +78 -0
- package/lib/agent-cli/lib/checklist.py +222 -0
- package/lib/agent-cli/lib/cognitive-lesson.js +476 -0
- package/lib/agent-cli/lib/completion.js +149 -0
- package/lib/agent-cli/lib/config.js +35 -0
- package/lib/agent-cli/lib/eslint-fix.js +238 -0
- package/lib/agent-cli/lib/evolution-signal.js +215 -0
- package/lib/agent-cli/lib/export.js +86 -0
- package/lib/agent-cli/lib/export.test.js +65 -0
- package/lib/agent-cli/lib/fix.js +337 -0
- package/lib/agent-cli/lib/fix.test.js +80 -0
- package/lib/agent-cli/lib/gemini-export.js +83 -0
- package/lib/agent-cli/lib/generate-registry.js +42 -0
- package/lib/agent-cli/lib/hooks/install-hooks.js +152 -0
- package/lib/agent-cli/lib/hooks/lint-learn.js +172 -0
- package/lib/agent-cli/lib/ignore.js +116 -0
- package/lib/agent-cli/lib/ignore.test.js +58 -0
- package/lib/agent-cli/lib/init.js +124 -0
- package/lib/agent-cli/lib/learn.js +255 -0
- package/lib/agent-cli/lib/learn.test.js +70 -0
- package/lib/agent-cli/lib/migrate-to-v4.js +322 -0
- package/lib/agent-cli/lib/proposals.js +199 -0
- package/lib/agent-cli/lib/proposals.test.js +56 -0
- package/lib/agent-cli/lib/recall.js +820 -0
- package/lib/agent-cli/lib/recall.test.js +107 -0
- package/lib/agent-cli/lib/selfevolution-bridge.js +167 -0
- package/lib/agent-cli/lib/session_manager.py +120 -0
- package/lib/agent-cli/lib/settings.js +227 -0
- package/lib/agent-cli/lib/skill-learn.js +296 -0
- package/lib/agent-cli/lib/stats.js +132 -0
- package/lib/agent-cli/lib/stats.test.js +94 -0
- package/lib/agent-cli/lib/types.js +33 -0
- package/lib/agent-cli/lib/ui/audit-ui.js +146 -0
- package/lib/agent-cli/lib/ui/backup-ui.js +107 -0
- package/lib/agent-cli/lib/ui/clack-helpers.js +317 -0
- package/lib/agent-cli/lib/ui/common.js +83 -0
- package/lib/agent-cli/lib/ui/completion-ui.js +126 -0
- package/lib/agent-cli/lib/ui/custom-select.js +69 -0
- package/lib/agent-cli/lib/ui/dashboard-ui.js +222 -0
- package/lib/agent-cli/lib/ui/evolution-signals-ui.js +107 -0
- package/lib/agent-cli/lib/ui/export-ui.js +94 -0
- package/lib/agent-cli/lib/ui/fix-all-ui.js +191 -0
- package/lib/agent-cli/lib/ui/help-ui.js +49 -0
- package/lib/agent-cli/lib/ui/index.js +199 -0
- package/lib/agent-cli/lib/ui/init-ui.js +56 -0
- package/lib/agent-cli/lib/ui/knowledge-ui.js +55 -0
- package/lib/agent-cli/lib/ui/learn-ui.js +706 -0
- package/lib/agent-cli/lib/ui/lessons-ui.js +148 -0
- package/lib/agent-cli/lib/ui/pretty.js +145 -0
- package/lib/agent-cli/lib/ui/proposals-ui.js +99 -0
- package/lib/agent-cli/lib/ui/recall-ui.js +342 -0
- package/lib/agent-cli/lib/ui/routing-demo.js +79 -0
- package/lib/agent-cli/lib/ui/routing-ui.js +325 -0
- package/lib/agent-cli/lib/ui/settings-ui.js +381 -0
- package/lib/agent-cli/lib/ui/stats-ui.js +123 -0
- package/lib/agent-cli/lib/ui/watch-ui.js +236 -0
- package/lib/agent-cli/lib/verify_all.py +327 -0
- package/lib/agent-cli/lib/watcher.js +181 -0
- package/lib/agent-cli/lib/watcher.test.js +85 -0
- package/lib/agent-cli/package.json +51 -0
- package/lib/agent-cli/scripts/adaptive_engine.js +381 -0
- package/lib/agent-cli/scripts/dashboard_server.js +224 -0
- package/lib/agent-cli/scripts/error_sensor.js +565 -0
- package/lib/agent-cli/scripts/learn_from_failure.js +225 -0
- package/lib/agent-cli/scripts/pattern_analyzer.js +781 -0
- package/lib/agent-cli/scripts/pre_execution_check.js +623 -0
- package/lib/agent-cli/scripts/rule_sharing.js +374 -0
- package/lib/agent-cli/scripts/skill_injector.js +387 -0
- package/lib/agent-cli/scripts/success_sensor.js +500 -0
- package/lib/agent-cli/scripts/user_correction_sensor.js +426 -0
- package/lib/agent-cli/services/auto-learn-service.js +247 -0
- package/lib/agent-cli/src/MIGRATION.md +418 -0
- package/lib/agent-cli/src/README.md +367 -0
- package/lib/agent-cli/src/core/evolution/evolution-signal.js +42 -0
- package/lib/agent-cli/src/core/evolution/index.js +17 -0
- package/lib/agent-cli/src/core/evolution/review-gate.js +40 -0
- package/lib/agent-cli/src/core/evolution/signal-detector.js +137 -0
- package/lib/agent-cli/src/core/evolution/signal-queue.js +79 -0
- package/lib/agent-cli/src/core/evolution/threshold-checker.js +79 -0
- package/lib/agent-cli/src/core/index.js +15 -0
- package/lib/agent-cli/src/core/learning/cognitive-enhancer.js +282 -0
- package/lib/agent-cli/src/core/learning/index.js +12 -0
- package/lib/agent-cli/src/core/learning/lesson-synthesizer.js +83 -0
- package/lib/agent-cli/src/core/scanning/index.js +14 -0
- package/lib/agent-cli/src/data/index.js +13 -0
- package/lib/agent-cli/src/data/repositories/index.js +8 -0
- package/lib/agent-cli/src/data/repositories/lesson-repository.js +130 -0
- package/lib/agent-cli/src/data/repositories/signal-repository.js +119 -0
- package/lib/agent-cli/src/data/storage/index.js +8 -0
- package/lib/agent-cli/src/data/storage/json-storage.js +64 -0
- package/lib/agent-cli/src/data/storage/yaml-storage.js +66 -0
- package/lib/agent-cli/src/infrastructure/index.js +13 -0
- package/lib/agent-cli/src/presentation/formatters/skill-formatter.js +232 -0
- package/lib/agent-cli/src/services/export-service.js +162 -0
- package/lib/agent-cli/src/services/index.js +13 -0
- package/lib/agent-cli/src/services/learning-service.js +99 -0
- package/lib/agent-cli/types/index.d.ts +343 -0
- package/lib/agent-cli/utils/benchmark.js +269 -0
- package/lib/agent-cli/utils/logger.js +303 -0
- package/lib/agent-cli/utils/ml_patterns.js +300 -0
- package/lib/agent-cli/utils/recovery.js +312 -0
- package/lib/agent-cli/utils/telemetry.js +290 -0
- package/lib/agentskillskit-cli/README.md +21 -0
- package/{node_modules/agentskillskit-cli/bin ā lib/agentskillskit-cli}/ag-smart.js +15 -15
- package/lib/agentskillskit-cli/package.json +51 -0
- package/package.json +19 -9
- /package/bin/{cli.js ā kit.js} +0 -0
- /package/{node_modules/agentskillskit-cli ā lib/agent-cli}/README.md +0 -0
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Smart Fix - Auto-fix Detected Violations
|
|
4
|
+
*
|
|
5
|
+
* Automatically fixes code violations based on learned patterns.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Comment out violations (safe mode)
|
|
9
|
+
* - Remove violations (aggressive mode)
|
|
10
|
+
* - Replace patterns (custom fix rules)
|
|
11
|
+
*
|
|
12
|
+
* Usage: agent fix <file|directory> [--mode safe|aggressive]
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import fs from "fs";
|
|
16
|
+
import path from "path";
|
|
17
|
+
import { loadKnowledge, saveKnowledge, scanFile, scanDirectory } from "./recall.js";
|
|
18
|
+
import { VERSION } from "./config.js";
|
|
19
|
+
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// FIX RULES
|
|
22
|
+
// ============================================================================
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Built-in fix rules for common patterns
|
|
26
|
+
*/
|
|
27
|
+
const FIX_RULES = {
|
|
28
|
+
// Console statements ā comment out
|
|
29
|
+
"console.log": {
|
|
30
|
+
type: "comment",
|
|
31
|
+
replacement: (line) => `// REMOVED: ${line.trim()}`
|
|
32
|
+
},
|
|
33
|
+
"console.warn": {
|
|
34
|
+
type: "comment",
|
|
35
|
+
replacement: (line) => `// REMOVED: ${line.trim()}`
|
|
36
|
+
},
|
|
37
|
+
"console.error": {
|
|
38
|
+
type: "comment",
|
|
39
|
+
replacement: (line) => `// REMOVED: ${line.trim()}`
|
|
40
|
+
},
|
|
41
|
+
"console.debug": {
|
|
42
|
+
type: "comment",
|
|
43
|
+
replacement: (line) => `// REMOVED: ${line.trim()}`
|
|
44
|
+
},
|
|
45
|
+
"console.info": {
|
|
46
|
+
type: "comment",
|
|
47
|
+
replacement: (line) => `// REMOVED: ${line.trim()}`
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
// var ā const
|
|
51
|
+
"\\bvar\\s+": {
|
|
52
|
+
type: "replace",
|
|
53
|
+
replacement: (line) => line.replace(/\bvar\s+/, "const ")
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
// == ā === (loose equality)
|
|
57
|
+
"[^!=]==[^=]": {
|
|
58
|
+
type: "replace",
|
|
59
|
+
replacement: (line) => line.replace(/([^!=])==([^=])/g, "$1===$2")
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
// != ā !== (loose inequality)
|
|
63
|
+
"[^!]=!=[^=]": {
|
|
64
|
+
type: "replace",
|
|
65
|
+
replacement: (line) => line.replace(/([^!])!=([^=])/g, "$1!==$2")
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
// debugger ā remove
|
|
69
|
+
"\\bdebugger\\b": {
|
|
70
|
+
type: "remove",
|
|
71
|
+
replacement: () => ""
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
// alert ā comment out
|
|
75
|
+
"\\balert\\(": {
|
|
76
|
+
type: "comment",
|
|
77
|
+
replacement: (line) => `// REMOVED: ${line.trim()}`
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
// TODO/FIXME in production ā warn only
|
|
81
|
+
"TODO|FIXME": {
|
|
82
|
+
type: "comment",
|
|
83
|
+
replacement: (line) => line // Leave as is, just flag
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
// Empty catch blocks ā add comment
|
|
87
|
+
"catch\\s*\\([^)]*\\)\\s*\\{\\s*\\}": {
|
|
88
|
+
type: "replace",
|
|
89
|
+
replacement: (line) => line.replace(/\{\s*\}/, "{ /* Intentionally empty */ }")
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
// Promise without catch ā add comment
|
|
93
|
+
"\\.then\\([^)]*\\)(?!.*\\.catch)": {
|
|
94
|
+
type: "comment",
|
|
95
|
+
replacement: (line) => `${line} // TODO: Add .catch()`
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
// Hardcoded localhost ā flag
|
|
99
|
+
"localhost:\\d+": {
|
|
100
|
+
type: "comment",
|
|
101
|
+
replacement: (line) => `// REVIEW: ${line.trim()} // Hardcoded URL`
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
// @ts-ignore ā flag for review
|
|
105
|
+
"@ts-ignore": {
|
|
106
|
+
type: "comment",
|
|
107
|
+
replacement: (line) => `${line} // TODO: Fix instead of ignoring`
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
// any type in TypeScript ā flag
|
|
111
|
+
": any": {
|
|
112
|
+
type: "comment",
|
|
113
|
+
replacement: (line) => `${line} // TODO: Replace 'any' with proper type`
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// ============================================================================
|
|
118
|
+
// FIX ENGINE
|
|
119
|
+
// ============================================================================
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Fix a single file
|
|
123
|
+
* @param {string} filePath
|
|
124
|
+
* @param {object} db - Knowledge base
|
|
125
|
+
* @param {string} mode - 'safe' or 'aggressive'
|
|
126
|
+
* @returns {{ file: string, fixes: number, backup: string }}
|
|
127
|
+
*/
|
|
128
|
+
function fixFile(filePath, db, mode = "safe") {
|
|
129
|
+
if (!fs.existsSync(filePath)) {
|
|
130
|
+
return { file: filePath, fixes: 0, error: "File not found" };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
134
|
+
const lines = content.split("\n");
|
|
135
|
+
let fixCount = 0;
|
|
136
|
+
let modified = false;
|
|
137
|
+
|
|
138
|
+
// Scan for violations
|
|
139
|
+
const result = scanFile(filePath, db, false);
|
|
140
|
+
|
|
141
|
+
if (result.violations.length === 0) {
|
|
142
|
+
return { file: filePath, fixes: 0 };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Create backup
|
|
146
|
+
const backupPath = filePath + ".backup";
|
|
147
|
+
fs.writeFileSync(backupPath, content, "utf8");
|
|
148
|
+
|
|
149
|
+
// Apply fixes
|
|
150
|
+
result.violations.forEach(({ lesson, matches }) => {
|
|
151
|
+
const rule = FIX_RULES[lesson.pattern] || {
|
|
152
|
+
type: mode === "aggressive" ? "remove" : "comment",
|
|
153
|
+
replacement: (line) => mode === "aggressive" ? "" : `// FLAGGED: ${line.trim()}`
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
matches.forEach(match => {
|
|
157
|
+
const lineIdx = match.line - 1;
|
|
158
|
+
if (lineIdx >= 0 && lineIdx < lines.length) {
|
|
159
|
+
const originalLine = lines[lineIdx];
|
|
160
|
+
|
|
161
|
+
if (rule.type === "remove") {
|
|
162
|
+
lines[lineIdx] = "";
|
|
163
|
+
fixCount++;
|
|
164
|
+
modified = true;
|
|
165
|
+
} else if (rule.type === "comment") {
|
|
166
|
+
if (!originalLine.trim().startsWith("//")) {
|
|
167
|
+
lines[lineIdx] = rule.replacement(originalLine);
|
|
168
|
+
fixCount++;
|
|
169
|
+
modified = true;
|
|
170
|
+
}
|
|
171
|
+
} else if (rule.type === "replace") {
|
|
172
|
+
const newLine = rule.replacement(originalLine);
|
|
173
|
+
if (newLine !== originalLine) {
|
|
174
|
+
lines[lineIdx] = newLine;
|
|
175
|
+
fixCount++;
|
|
176
|
+
modified = true;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// Write fixed content
|
|
184
|
+
if (modified) {
|
|
185
|
+
const newContent = lines.filter(l => l !== "" || mode !== "aggressive").join("\n");
|
|
186
|
+
fs.writeFileSync(filePath, newContent, "utf8");
|
|
187
|
+
} else {
|
|
188
|
+
// Remove backup if no changes
|
|
189
|
+
fs.unlinkSync(backupPath);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
file: filePath,
|
|
194
|
+
fixes: fixCount,
|
|
195
|
+
backup: modified ? backupPath : null
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Fix all files in directory
|
|
201
|
+
*/
|
|
202
|
+
function fixDirectory(dirPath, db, mode = "safe") {
|
|
203
|
+
const results = [];
|
|
204
|
+
const extensions = [".js", ".ts", ".tsx", ".jsx", ".mjs"];
|
|
205
|
+
|
|
206
|
+
function walk(dir) {
|
|
207
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
208
|
+
|
|
209
|
+
for (const entry of entries) {
|
|
210
|
+
const fullPath = path.join(dir, entry.name);
|
|
211
|
+
|
|
212
|
+
if (entry.isDirectory()) {
|
|
213
|
+
if (!["node_modules", ".git", "dist", "build"].includes(entry.name)) {
|
|
214
|
+
walk(fullPath);
|
|
215
|
+
}
|
|
216
|
+
} else if (entry.isFile()) {
|
|
217
|
+
const ext = path.extname(entry.name);
|
|
218
|
+
if (extensions.includes(ext)) {
|
|
219
|
+
const result = fixFile(fullPath, db, mode);
|
|
220
|
+
if (result.fixes > 0) {
|
|
221
|
+
results.push(result);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (fs.statSync(dirPath).isDirectory()) {
|
|
229
|
+
walk(dirPath);
|
|
230
|
+
} else {
|
|
231
|
+
const result = fixFile(dirPath, db, mode);
|
|
232
|
+
if (result.fixes > 0) {
|
|
233
|
+
results.push(result);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return results;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// ============================================================================
|
|
241
|
+
// CLI
|
|
242
|
+
// ============================================================================
|
|
243
|
+
|
|
244
|
+
async function main() {
|
|
245
|
+
const args = process.argv.slice(2);
|
|
246
|
+
|
|
247
|
+
if (args.length === 0 || args.includes("--help")) {
|
|
248
|
+
console.log(`
|
|
249
|
+
š§ Smart Fix v${VERSION} - Auto-fix Violations
|
|
250
|
+
|
|
251
|
+
Usage:
|
|
252
|
+
agent fix <file|directory> [options]
|
|
253
|
+
|
|
254
|
+
Options:
|
|
255
|
+
--mode safe Comment out violations (default)
|
|
256
|
+
--mode aggressive Remove violations entirely
|
|
257
|
+
--eslint Also run ESLint --fix
|
|
258
|
+
--dry-run Show what would be fixed without changing files
|
|
259
|
+
--help Show this help
|
|
260
|
+
|
|
261
|
+
Examples:
|
|
262
|
+
agent fix src/
|
|
263
|
+
agent fix app.js --mode aggressive
|
|
264
|
+
agent fix src/ --eslint
|
|
265
|
+
`);
|
|
266
|
+
process.exit(0);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const target = args[0];
|
|
270
|
+
const mode = args.includes("--mode")
|
|
271
|
+
? args[args.indexOf("--mode") + 1]
|
|
272
|
+
: "safe";
|
|
273
|
+
const dryRun = args.includes("--dry-run");
|
|
274
|
+
const useEslint = args.includes("--eslint");
|
|
275
|
+
|
|
276
|
+
const db = loadKnowledge();
|
|
277
|
+
|
|
278
|
+
if (!db.lessons || db.lessons.length === 0) {
|
|
279
|
+
console.log("ā¹ļø No lessons learned yet. Nothing to fix.");
|
|
280
|
+
process.exit(0);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
console.log(`\nš§ Smart Fix v${VERSION}`);
|
|
284
|
+
console.log(`š Target: ${target}`);
|
|
285
|
+
console.log(`šÆ Mode: ${mode}`);
|
|
286
|
+
if (useEslint) console.log(`š§ ESLint: enabled`);
|
|
287
|
+
console.log(`${"ā".repeat(50)}\n`);
|
|
288
|
+
|
|
289
|
+
// Run ESLint fix first if enabled
|
|
290
|
+
if (useEslint && !dryRun) {
|
|
291
|
+
try {
|
|
292
|
+
const { runEslintFix } = await import("./eslint-fix.js");
|
|
293
|
+
runEslintFix(target);
|
|
294
|
+
} catch (e) {
|
|
295
|
+
console.log(`ā ļø ESLint fix skipped: ${e.message}`);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (dryRun) {
|
|
300
|
+
console.log("š DRY RUN - showing what would be fixed:\n");
|
|
301
|
+
const scanResults = scanDirectory(target, db);
|
|
302
|
+
scanResults.forEach(r => {
|
|
303
|
+
console.log(`š ${path.relative(process.cwd(), r.file)}`);
|
|
304
|
+
r.violations.forEach(v => {
|
|
305
|
+
console.log(` Would fix ${v.matches.length} violation(s) of [${v.lesson.id}]`);
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
process.exit(0);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const results = fixDirectory(target, db, mode);
|
|
312
|
+
|
|
313
|
+
if (results.length === 0) {
|
|
314
|
+
console.log("ā
No pattern violations to fix.");
|
|
315
|
+
process.exit(0);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
let totalFixes = 0;
|
|
319
|
+
results.forEach(r => {
|
|
320
|
+
totalFixes += r.fixes;
|
|
321
|
+
console.log(`ā
${path.relative(process.cwd(), r.file)}: ${r.fixes} fix(es)`);
|
|
322
|
+
if (r.backup) {
|
|
323
|
+
console.log(` š¦ Backup: ${path.basename(r.backup)}`);
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
console.log(`\n${"ā".repeat(50)}`);
|
|
328
|
+
console.log(`š Fixed ${totalFixes} violation(s) in ${results.length} file(s)`);
|
|
329
|
+
console.log(`š” Backups created with .backup extension`);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Run if executed directly (as async)
|
|
333
|
+
if (process.argv[1].includes("fix")) {
|
|
334
|
+
main().catch(console.error);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export { fixFile, fixDirectory, FIX_RULES };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Tests for fix.js functionality
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
5
|
+
import fs from "fs";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import os from "os";
|
|
8
|
+
|
|
9
|
+
const TEST_DIR = path.join(os.tmpdir(), "agent-skill-kit-fix-test");
|
|
10
|
+
|
|
11
|
+
describe("Fix - Pattern Replacement", () => {
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
fs.mkdirSync(TEST_DIR, { recursive: true });
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
fs.rmSync(TEST_DIR, { recursive: true, force: true });
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("comments out console.log statements", () => {
|
|
21
|
+
const line = 'console.log("debug");';
|
|
22
|
+
const fixed = `// ${line}`;
|
|
23
|
+
expect(fixed).toBe('// console.log("debug");');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("replaces var with const", () => {
|
|
27
|
+
const line = "var x = 1;";
|
|
28
|
+
const fixed = line.replace(/\bvar\s+/, "const ");
|
|
29
|
+
expect(fixed).toBe("const x = 1;");
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("replaces == with ===", () => {
|
|
33
|
+
const line = "if (a == b) {";
|
|
34
|
+
const fixed = line.replace(/([^!=])==([^=])/g, "$1===$2");
|
|
35
|
+
expect(fixed).toBe("if (a === b) {");
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("removes debugger statements", () => {
|
|
39
|
+
const lines = [
|
|
40
|
+
"const x = 1;",
|
|
41
|
+
"debugger;",
|
|
42
|
+
"const y = 2;"
|
|
43
|
+
];
|
|
44
|
+
const filtered = lines.filter(l => !/\bdebugger\b/.test(l));
|
|
45
|
+
expect(filtered.length).toBe(2);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe("Fix - Backup Creation", () => {
|
|
50
|
+
beforeEach(() => {
|
|
51
|
+
fs.mkdirSync(TEST_DIR, { recursive: true });
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
afterEach(() => {
|
|
55
|
+
fs.rmSync(TEST_DIR, { recursive: true, force: true });
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("creates backup file with .bak extension", () => {
|
|
59
|
+
const testFile = path.join(TEST_DIR, "test.js");
|
|
60
|
+
const backupFile = path.join(TEST_DIR, "test.js.bak");
|
|
61
|
+
|
|
62
|
+
fs.writeFileSync(testFile, "original content", "utf8");
|
|
63
|
+
fs.copyFileSync(testFile, backupFile);
|
|
64
|
+
|
|
65
|
+
expect(fs.existsSync(backupFile)).toBe(true);
|
|
66
|
+
expect(fs.readFileSync(backupFile, "utf8")).toBe("original content");
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe("Fix - Mode Selection", () => {
|
|
71
|
+
it("identifies safe mode correctly", () => {
|
|
72
|
+
const mode = "safe";
|
|
73
|
+
expect(mode === "safe").toBe(true);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("identifies aggressive mode correctly", () => {
|
|
77
|
+
const mode = "aggressive";
|
|
78
|
+
expect(mode === "aggressive").toBe(true);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Export Skills to Gemini - CLI Tool
|
|
4
|
+
*
|
|
5
|
+
* Gemini-specific export functionality
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { LessonRepository } from '../src/data/repositories/lesson-repository.js';
|
|
9
|
+
import { YamlStorage } from '../src/data/storage/yaml-storage.js';
|
|
10
|
+
import { LearningService } from '../src/services/learning-service.js';
|
|
11
|
+
import { SkillFormatter } from '../src/presentation/formatters/skill-formatter.js';
|
|
12
|
+
import { ExportService } from '../src/services/export-service.js';
|
|
13
|
+
import { KNOWLEDGE_DIR } from './config.js';
|
|
14
|
+
import path from 'path';
|
|
15
|
+
import { fileURLToPath } from 'url';
|
|
16
|
+
|
|
17
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
18
|
+
const PROJECT_ROOT = path.join(__dirname, '../../..');
|
|
19
|
+
const SKILLS_DIR = path.join(PROJECT_ROOT, '.agent/skills');
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Export all mature skills
|
|
23
|
+
*/
|
|
24
|
+
export async function exportGeminiSkills() {
|
|
25
|
+
console.log('š Exporting Mature Skills to Gemini\n');
|
|
26
|
+
|
|
27
|
+
const storage = new YamlStorage(KNOWLEDGE_DIR);
|
|
28
|
+
const repository = new LessonRepository(storage);
|
|
29
|
+
const learningService = new LearningService(repository);
|
|
30
|
+
const skillFormatter = new SkillFormatter();
|
|
31
|
+
const exportService = new ExportService(learningService, skillFormatter);
|
|
32
|
+
|
|
33
|
+
const stats = await exportService.getExportStats();
|
|
34
|
+
|
|
35
|
+
console.log('š Export Statistics:');
|
|
36
|
+
console.log(` Total lessons: ${stats.total}`);
|
|
37
|
+
console.log(` Exportable (MATURE/IDEAL, ā„80%): ${stats.exportable}\n`);
|
|
38
|
+
|
|
39
|
+
if (stats.exportable === 0) {
|
|
40
|
+
console.log('ā¹ļø No skills ready for export.\n');
|
|
41
|
+
return { skills: [], count: 0 };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const exported = await exportService.exportMatureSkills(SKILLS_DIR, 0.8);
|
|
45
|
+
|
|
46
|
+
console.log(`ā
Successfully exported ${exported.length} skill(s) to Gemini:\n`);
|
|
47
|
+
exported.forEach(skill => {
|
|
48
|
+
console.log(` ā ${skill.filename}`);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
console.log('\nš Export Complete!');
|
|
52
|
+
console.log('š” Gemini AI will now use these skills when coding.\n');
|
|
53
|
+
|
|
54
|
+
return { skills: exported, count: exported.length };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Preview exportable skills
|
|
59
|
+
*/
|
|
60
|
+
export async function previewGeminiSkills() {
|
|
61
|
+
const storage = new YamlStorage(KNOWLEDGE_DIR);
|
|
62
|
+
const repository = new LessonRepository(storage);
|
|
63
|
+
const learningService = new LearningService(repository);
|
|
64
|
+
const skillFormatter = new SkillFormatter();
|
|
65
|
+
const exportService = new ExportService(learningService, skillFormatter);
|
|
66
|
+
|
|
67
|
+
const preview = await exportService.previewMatureSkills(0.8);
|
|
68
|
+
|
|
69
|
+
if (preview.length === 0) {
|
|
70
|
+
console.log('ā¹ļø No skills ready for export.\n');
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
console.log(`\nā
${preview.length} skill(s) ready for Gemini:\n`);
|
|
75
|
+
|
|
76
|
+
preview.forEach(skill => {
|
|
77
|
+
console.log(`š ${skill.id}: ${skill.title}`);
|
|
78
|
+
console.log(` ${skill.state} (${(skill.confidence * 100).toFixed(0)}%)`);
|
|
79
|
+
console.log(` ā ${skill.filename}\n`);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
return preview;
|
|
83
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
const SKILLS_DIR = path.join(__dirname, '../../..', '.agent', 'skills');
|
|
5
|
+
const OUTPUT_FILE = path.join(SKILLS_DIR, 'registry.json');
|
|
6
|
+
|
|
7
|
+
const registry = {
|
|
8
|
+
updatedAt: new Date().toISOString(),
|
|
9
|
+
skills: []
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
if (fs.existsSync(SKILLS_DIR)) {
|
|
13
|
+
const skills = fs.readdirSync(SKILLS_DIR, { withFileTypes: true })
|
|
14
|
+
.filter(dirent => dirent.isDirectory())
|
|
15
|
+
.map(dirent => dirent.name);
|
|
16
|
+
|
|
17
|
+
skills.forEach(skill => {
|
|
18
|
+
const skillPath = path.join(SKILLS_DIR, skill);
|
|
19
|
+
const skillData = {
|
|
20
|
+
name: skill,
|
|
21
|
+
rules: [],
|
|
22
|
+
scripts: []
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// Find rules
|
|
26
|
+
const rulesDir = path.join(skillPath, 'rules');
|
|
27
|
+
if (fs.existsSync(rulesDir)) {
|
|
28
|
+
skillData.rules = fs.readdirSync(rulesDir).filter(f => f.endsWith('.md'));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Find scripts
|
|
32
|
+
const scriptsDir = path.join(skillPath, 'scripts');
|
|
33
|
+
if (fs.existsSync(scriptsDir)) {
|
|
34
|
+
skillData.scripts = fs.readdirSync(scriptsDir).filter(f => f.endsWith('.js') || f.endsWith('.py'));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
registry.skills.push(skillData);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
fs.writeFileSync(OUTPUT_FILE, JSON.stringify(registry, null, 2));
|
|
42
|
+
console.log(`Registry generated at ${OUTPUT_FILE}`);
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Git Hooks Installer
|
|
4
|
+
*
|
|
5
|
+
* Installs pre-commit hook that runs recall on staged files.
|
|
6
|
+
*
|
|
7
|
+
* Usage: agent install-hooks
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import fs from "fs";
|
|
11
|
+
import path from "path";
|
|
12
|
+
import { VERSION } from "../config.js";
|
|
13
|
+
|
|
14
|
+
// ============================================================================
|
|
15
|
+
// HOOK TEMPLATES
|
|
16
|
+
// ============================================================================
|
|
17
|
+
|
|
18
|
+
const PRE_COMMIT_HOOK = `#!/bin/sh
|
|
19
|
+
# Smart Agent Pre-Commit Hook v${VERSION}
|
|
20
|
+
|
|
21
|
+
# Get staged JS/TS files
|
|
22
|
+
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E "\\\\.(js|ts|tsx|jsx|mjs)$")
|
|
23
|
+
|
|
24
|
+
if [ -z "$STAGED_FILES" ]; then
|
|
25
|
+
exit 0
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# Run recall (Clack handles all output)
|
|
29
|
+
npx agent recall . 2>/dev/null
|
|
30
|
+
exit $?
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
// ============================================================================
|
|
34
|
+
// INSTALLER
|
|
35
|
+
// ============================================================================
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Find .git directory
|
|
39
|
+
* @returns {string|null}
|
|
40
|
+
*/
|
|
41
|
+
function findGitDir() {
|
|
42
|
+
let dir = process.cwd();
|
|
43
|
+
|
|
44
|
+
while (dir !== path.dirname(dir)) {
|
|
45
|
+
const gitDir = path.join(dir, ".git");
|
|
46
|
+
if (fs.existsSync(gitDir)) {
|
|
47
|
+
return gitDir;
|
|
48
|
+
}
|
|
49
|
+
dir = path.dirname(dir);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Install git hooks
|
|
57
|
+
*/
|
|
58
|
+
function installHooks() {
|
|
59
|
+
console.log(`\nš§ Smart Agent Hooks Installer v${VERSION}\n`);
|
|
60
|
+
|
|
61
|
+
const gitDir = findGitDir();
|
|
62
|
+
|
|
63
|
+
if (!gitDir) {
|
|
64
|
+
console.log("ā Not a git repository. Initialize git first:");
|
|
65
|
+
console.log(" git init\n");
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const hooksDir = path.join(gitDir, "hooks");
|
|
70
|
+
const preCommitPath = path.join(hooksDir, "pre-commit");
|
|
71
|
+
|
|
72
|
+
// Create hooks directory if missing
|
|
73
|
+
if (!fs.existsSync(hooksDir)) {
|
|
74
|
+
fs.mkdirSync(hooksDir, { recursive: true });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Backup existing hook
|
|
78
|
+
if (fs.existsSync(preCommitPath)) {
|
|
79
|
+
const backupPath = preCommitPath + ".backup";
|
|
80
|
+
fs.copyFileSync(preCommitPath, backupPath);
|
|
81
|
+
console.log(`š¦ Backed up existing hook to: pre-commit.backup`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Write new hook
|
|
85
|
+
fs.writeFileSync(preCommitPath, PRE_COMMIT_HOOK, { mode: 0o755 });
|
|
86
|
+
|
|
87
|
+
console.log("ā
Installed pre-commit hook");
|
|
88
|
+
console.log(` Location: ${preCommitPath}\n`);
|
|
89
|
+
|
|
90
|
+
console.log("š What it does:");
|
|
91
|
+
console.log(" ⢠Runs on every commit");
|
|
92
|
+
console.log(" ⢠Checks staged JS/TS files against memory");
|
|
93
|
+
console.log(" ⢠Shows violations (does NOT block commits)\n");
|
|
94
|
+
|
|
95
|
+
console.log("š” Tips:");
|
|
96
|
+
console.log(" ⢠Skip hook: git commit --no-verify");
|
|
97
|
+
console.log(" ⢠Uninstall: rm .git/hooks/pre-commit\n");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Uninstall hooks
|
|
102
|
+
*/
|
|
103
|
+
function uninstallHooks() {
|
|
104
|
+
const gitDir = findGitDir();
|
|
105
|
+
|
|
106
|
+
if (!gitDir) {
|
|
107
|
+
console.log("ā Not a git repository.\n");
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const preCommitPath = path.join(gitDir, "hooks", "pre-commit");
|
|
112
|
+
|
|
113
|
+
if (fs.existsSync(preCommitPath)) {
|
|
114
|
+
fs.unlinkSync(preCommitPath);
|
|
115
|
+
console.log("ā
Removed pre-commit hook.\n");
|
|
116
|
+
|
|
117
|
+
// Restore backup if exists
|
|
118
|
+
const backupPath = preCommitPath + ".backup";
|
|
119
|
+
if (fs.existsSync(backupPath)) {
|
|
120
|
+
fs.renameSync(backupPath, preCommitPath);
|
|
121
|
+
console.log("š¦ Restored previous hook from backup.\n");
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
console.log("ā¹ļø No hook installed.\n");
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ============================================================================
|
|
129
|
+
// CLI
|
|
130
|
+
// ============================================================================
|
|
131
|
+
|
|
132
|
+
const args = process.argv.slice(2);
|
|
133
|
+
|
|
134
|
+
if (args.includes("--help")) {
|
|
135
|
+
console.log(`
|
|
136
|
+
š§ Smart Agent Hooks Installer
|
|
137
|
+
|
|
138
|
+
Usage:
|
|
139
|
+
agent install-hooks Install git hooks
|
|
140
|
+
agent install-hooks --remove Remove installed hooks
|
|
141
|
+
|
|
142
|
+
The pre-commit hook checks staged files against learned
|
|
143
|
+
patterns before each commit.
|
|
144
|
+
`);
|
|
145
|
+
process.exit(0);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (args.includes("--remove") || args.includes("--uninstall")) {
|
|
149
|
+
uninstallHooks();
|
|
150
|
+
} else {
|
|
151
|
+
installHooks();
|
|
152
|
+
}
|