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.
- package/README.md +1 -1
- package/bin/lib/commands/install.js +119 -242
- package/package.json +3 -4
- package/lib/agent-cli/bin/agent.js +0 -187
- package/lib/agent-cli/dashboard/dashboard_server.js +0 -312
- package/lib/agent-cli/lib/ab-testing.js +0 -364
- package/lib/agent-cli/lib/audit.js +0 -154
- package/lib/agent-cli/lib/audit.test.js +0 -100
- package/lib/agent-cli/lib/auto-learn.js +0 -319
- package/lib/agent-cli/lib/backup.js +0 -138
- package/lib/agent-cli/lib/backup.test.js +0 -78
- package/lib/agent-cli/lib/causality-engine.js +0 -331
- package/lib/agent-cli/lib/cognitive-lesson.js +0 -476
- package/lib/agent-cli/lib/completion.js +0 -149
- package/lib/agent-cli/lib/config.js +0 -35
- package/lib/agent-cli/lib/dashboard-data.js +0 -380
- package/lib/agent-cli/lib/eslint-fix.js +0 -238
- package/lib/agent-cli/lib/evolution-signal.js +0 -215
- package/lib/agent-cli/lib/export.js +0 -86
- package/lib/agent-cli/lib/export.test.js +0 -65
- package/lib/agent-cli/lib/fix.js +0 -337
- package/lib/agent-cli/lib/fix.test.js +0 -80
- package/lib/agent-cli/lib/gemini-export.js +0 -83
- package/lib/agent-cli/lib/generate-registry.js +0 -42
- package/lib/agent-cli/lib/hooks/install-hooks.js +0 -152
- package/lib/agent-cli/lib/hooks/lint-learn.js +0 -172
- package/lib/agent-cli/lib/icons.js +0 -93
- package/lib/agent-cli/lib/ignore.js +0 -116
- package/lib/agent-cli/lib/ignore.test.js +0 -58
- package/lib/agent-cli/lib/init.js +0 -124
- package/lib/agent-cli/lib/knowledge-index.js +0 -326
- package/lib/agent-cli/lib/knowledge-metrics.js +0 -335
- package/lib/agent-cli/lib/knowledge-retention.js +0 -398
- package/lib/agent-cli/lib/knowledge-validator.js +0 -312
- package/lib/agent-cli/lib/learn.js +0 -255
- package/lib/agent-cli/lib/learn.test.js +0 -70
- package/lib/agent-cli/lib/metrics-collector.js +0 -410
- package/lib/agent-cli/lib/proposals.js +0 -199
- package/lib/agent-cli/lib/proposals.test.js +0 -56
- package/lib/agent-cli/lib/recall.js +0 -835
- package/lib/agent-cli/lib/recall.test.js +0 -107
- package/lib/agent-cli/lib/reinforcement.js +0 -299
- package/lib/agent-cli/lib/selfevolution-bridge.js +0 -167
- package/lib/agent-cli/lib/settings.js +0 -203
- package/lib/agent-cli/lib/skill-generator.js +0 -379
- package/lib/agent-cli/lib/skill-learn.js +0 -296
- package/lib/agent-cli/lib/stats.js +0 -132
- package/lib/agent-cli/lib/stats.test.js +0 -94
- package/lib/agent-cli/lib/types.js +0 -33
- package/lib/agent-cli/lib/ui/audit-ui.js +0 -146
- package/lib/agent-cli/lib/ui/backup-ui.js +0 -107
- package/lib/agent-cli/lib/ui/clack-helpers.js +0 -317
- package/lib/agent-cli/lib/ui/common.js +0 -83
- package/lib/agent-cli/lib/ui/completion-ui.js +0 -126
- package/lib/agent-cli/lib/ui/custom-select.js +0 -69
- package/lib/agent-cli/lib/ui/dashboard-ui.js +0 -222
- package/lib/agent-cli/lib/ui/evolution-signals-ui.js +0 -107
- package/lib/agent-cli/lib/ui/export-ui.js +0 -94
- package/lib/agent-cli/lib/ui/fix-all-ui.js +0 -191
- package/lib/agent-cli/lib/ui/help-ui.js +0 -49
- package/lib/agent-cli/lib/ui/index.js +0 -199
- package/lib/agent-cli/lib/ui/init-ui.js +0 -56
- package/lib/agent-cli/lib/ui/knowledge-ui.js +0 -55
- package/lib/agent-cli/lib/ui/learn-ui.js +0 -706
- package/lib/agent-cli/lib/ui/lessons-ui.js +0 -148
- package/lib/agent-cli/lib/ui/pretty.js +0 -145
- package/lib/agent-cli/lib/ui/proposals-ui.js +0 -99
- package/lib/agent-cli/lib/ui/recall-ui.js +0 -342
- package/lib/agent-cli/lib/ui/routing-demo.js +0 -79
- package/lib/agent-cli/lib/ui/routing-ui.js +0 -325
- package/lib/agent-cli/lib/ui/settings-ui.js +0 -381
- package/lib/agent-cli/lib/ui/stats-ui.js +0 -123
- package/lib/agent-cli/lib/ui/watch-ui.js +0 -236
- package/lib/agent-cli/lib/watcher.js +0 -181
- package/lib/agent-cli/lib/watcher.test.js +0 -85
- package/lib/agent-cli/src/MIGRATION.md +0 -418
- package/lib/agent-cli/src/README.md +0 -367
- package/lib/agent-cli/src/core/evolution/evolution-signal.js +0 -42
- package/lib/agent-cli/src/core/evolution/index.js +0 -17
- package/lib/agent-cli/src/core/evolution/review-gate.js +0 -40
- package/lib/agent-cli/src/core/evolution/signal-detector.js +0 -137
- package/lib/agent-cli/src/core/evolution/signal-queue.js +0 -79
- package/lib/agent-cli/src/core/evolution/threshold-checker.js +0 -79
- package/lib/agent-cli/src/core/index.js +0 -15
- package/lib/agent-cli/src/core/learning/cognitive-enhancer.js +0 -282
- package/lib/agent-cli/src/core/learning/index.js +0 -12
- package/lib/agent-cli/src/core/learning/lesson-synthesizer.js +0 -83
- package/lib/agent-cli/src/core/scanning/index.js +0 -14
- package/lib/agent-cli/src/data/index.js +0 -13
- package/lib/agent-cli/src/data/repositories/index.js +0 -8
- package/lib/agent-cli/src/data/repositories/lesson-repository.js +0 -130
- package/lib/agent-cli/src/data/repositories/signal-repository.js +0 -119
- package/lib/agent-cli/src/data/storage/index.js +0 -8
- package/lib/agent-cli/src/data/storage/json-storage.js +0 -64
- package/lib/agent-cli/src/data/storage/yaml-storage.js +0 -66
- package/lib/agent-cli/src/infrastructure/index.js +0 -13
- package/lib/agent-cli/src/presentation/formatters/skill-formatter.js +0 -232
- package/lib/agent-cli/src/services/export-service.js +0 -162
- package/lib/agent-cli/src/services/index.js +0 -13
- package/lib/agent-cli/src/services/learning-service.js +0 -99
|
@@ -1,80 +0,0 @@
|
|
|
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
|
-
});
|
|
@@ -1,83 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
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}`);
|
|
@@ -1,152 +0,0 @@
|
|
|
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
|
-
# PikaKit 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🔧 PikaKit 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
|
-
🔧 PikaKit 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
|
-
}
|
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Lint Learn - Auto-Learn from ESLint Output (CLI v3.3.0)
|
|
4
|
-
*
|
|
5
|
-
* Parses ESLint JSON output and creates lessons automatically.
|
|
6
|
-
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* npx eslint . --format json | agent lint-learn
|
|
9
|
-
* npx eslint . --format json > output.json && agent lint-learn output.json
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import fs from "fs";
|
|
13
|
-
import { loadKnowledge, saveKnowledge } from "../recall.js";
|
|
14
|
-
|
|
15
|
-
// ============================================================================
|
|
16
|
-
// ESLINT PARSER
|
|
17
|
-
// ============================================================================
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Parse ESLint JSON output and extract rules
|
|
21
|
-
* @param {string} jsonContent
|
|
22
|
-
* @returns {Array<{ rule: string, count: number, message: string }>}
|
|
23
|
-
*/
|
|
24
|
-
function parseEslintOutput(jsonContent) {
|
|
25
|
-
const ruleStats = {};
|
|
26
|
-
|
|
27
|
-
try {
|
|
28
|
-
const results = JSON.parse(jsonContent);
|
|
29
|
-
|
|
30
|
-
results.forEach(file => {
|
|
31
|
-
if (!file.messages) return;
|
|
32
|
-
|
|
33
|
-
file.messages.forEach(msg => {
|
|
34
|
-
if (!msg.ruleId) return;
|
|
35
|
-
|
|
36
|
-
if (!ruleStats[msg.ruleId]) {
|
|
37
|
-
ruleStats[msg.ruleId] = {
|
|
38
|
-
rule: msg.ruleId,
|
|
39
|
-
count: 0,
|
|
40
|
-
message: msg.message,
|
|
41
|
-
severity: msg.severity === 2 ? "ERROR" : "WARNING"
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
ruleStats[msg.ruleId].count++;
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
} catch (e) {
|
|
48
|
-
console.error("❌ Failed to parse ESLint JSON output:", e.message);
|
|
49
|
-
process.exit(1);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return Object.values(ruleStats).sort((a, b) => b.count - a.count);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Convert ESLint rule to regex pattern
|
|
57
|
-
* @param {string} rule - ESLint rule ID
|
|
58
|
-
* @returns {string}
|
|
59
|
-
*/
|
|
60
|
-
function ruleToPattern(rule) {
|
|
61
|
-
// Map common ESLint rules to regex patterns
|
|
62
|
-
const patterns = {
|
|
63
|
-
"no-console": "console\\.(log|warn|error|info|debug)",
|
|
64
|
-
"no-debugger": "\\bdebugger\\b",
|
|
65
|
-
"no-var": "\\bvar\\s+",
|
|
66
|
-
"no-unused-vars": null, // Can't easily detect with regex
|
|
67
|
-
"no-undef": null,
|
|
68
|
-
"eqeqeq": "[^!=]==[^=]",
|
|
69
|
-
"no-eval": "\\beval\\s*\\(",
|
|
70
|
-
"no-alert": "\\balert\\s*\\("
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
return patterns[rule] || null;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// ============================================================================
|
|
77
|
-
// MAIN
|
|
78
|
-
// ============================================================================
|
|
79
|
-
|
|
80
|
-
async function main() {
|
|
81
|
-
const args = process.argv.slice(2);
|
|
82
|
-
let jsonContent = "";
|
|
83
|
-
|
|
84
|
-
if (args.includes("--help")) {
|
|
85
|
-
console.log(`
|
|
86
|
-
🔧 Lint Learn - Auto-Learn from ESLint
|
|
87
|
-
|
|
88
|
-
Usage:
|
|
89
|
-
npx eslint . --format json | agent lint-learn
|
|
90
|
-
agent lint-learn eslint-output.json
|
|
91
|
-
|
|
92
|
-
Creates lessons from ESLint violations automatically.
|
|
93
|
-
`);
|
|
94
|
-
process.exit(0);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Read from file or stdin
|
|
98
|
-
if (args[0] && !args[0].startsWith("-")) {
|
|
99
|
-
if (fs.existsSync(args[0])) {
|
|
100
|
-
jsonContent = fs.readFileSync(args[0], "utf8");
|
|
101
|
-
} else {
|
|
102
|
-
console.error(`❌ File not found: ${args[0]}`);
|
|
103
|
-
process.exit(1);
|
|
104
|
-
}
|
|
105
|
-
} else {
|
|
106
|
-
// Read from stdin
|
|
107
|
-
const chunks = [];
|
|
108
|
-
process.stdin.setEncoding("utf8");
|
|
109
|
-
|
|
110
|
-
for await (const chunk of process.stdin) {
|
|
111
|
-
chunks.push(chunk);
|
|
112
|
-
}
|
|
113
|
-
jsonContent = chunks.join("");
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (!jsonContent.trim()) {
|
|
117
|
-
console.log("ℹ️ No input received. Pipe ESLint JSON output or provide a file.");
|
|
118
|
-
process.exit(0);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const rules = parseEslintOutput(jsonContent);
|
|
122
|
-
|
|
123
|
-
if (rules.length === 0) {
|
|
124
|
-
console.log("✅ No ESLint violations found.");
|
|
125
|
-
process.exit(0);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
console.log(`\n🔧 Lint Learn - Found ${rules.length} unique ESLint rule(s)\n`);
|
|
129
|
-
|
|
130
|
-
const db = loadKnowledge();
|
|
131
|
-
let added = 0;
|
|
132
|
-
|
|
133
|
-
rules.forEach(r => {
|
|
134
|
-
const pattern = ruleToPattern(r.rule);
|
|
135
|
-
|
|
136
|
-
if (!pattern) {
|
|
137
|
-
console.log(`⏭️ Skipped: ${r.rule} (no regex pattern available)`);
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Check if already exists
|
|
142
|
-
const exists = db.lessons.some(l => l.pattern === pattern);
|
|
143
|
-
if (exists) {
|
|
144
|
-
console.log(`⏭️ Skipped: ${r.rule} (already in memory)`);
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const id = `LEARN-${String(db.lessons.length + 1).padStart(3, "0")}`;
|
|
149
|
-
|
|
150
|
-
db.lessons.push({
|
|
151
|
-
id,
|
|
152
|
-
pattern,
|
|
153
|
-
message: `ESLint: ${r.rule} - ${r.message}`,
|
|
154
|
-
severity: r.severity,
|
|
155
|
-
source: "eslint",
|
|
156
|
-
hitCount: r.count,
|
|
157
|
-
addedAt: new Date().toISOString()
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
added++;
|
|
161
|
-
console.log(`✅ Added: [${id}] ${r.rule} (${r.count} occurrences)`);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
if (added > 0) {
|
|
165
|
-
saveKnowledge(db);
|
|
166
|
-
console.log(`\n🎓 Learned ${added} new lesson(s) from ESLint output.\n`);
|
|
167
|
-
} else {
|
|
168
|
-
console.log("\nℹ️ No new lessons to add.\n");
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
main();
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Windows-safe icons utility
|
|
3
|
-
*
|
|
4
|
-
* Provides ASCII fallback for emojis/Unicode when running on Windows Console
|
|
5
|
-
* that doesn't support UTF-8 properly.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
// Check if we're in a Windows environment with potential encoding issues
|
|
9
|
-
const isWindowsConsole = process.platform === 'win32' &&
|
|
10
|
-
(!process.env.WT_SESSION && !process.env.TERM_PROGRAM);
|
|
11
|
-
|
|
12
|
-
// Icon mappings: [unicode, ascii fallback]
|
|
13
|
-
const ICONS = {
|
|
14
|
-
brain: ['🧠', '[*]'],
|
|
15
|
-
check: ['✓', '[v]'],
|
|
16
|
-
cross: ['✗', '[x]'],
|
|
17
|
-
warning: ['⚠️', '[!]'],
|
|
18
|
-
info: ['ℹ️', '[i]'],
|
|
19
|
-
arrow: ['›', '>'],
|
|
20
|
-
star: ['⭐', '*'],
|
|
21
|
-
rocket: ['🚀', '>>'],
|
|
22
|
-
fire: ['🔥', '!!'],
|
|
23
|
-
party: ['🎉', ':)'],
|
|
24
|
-
magnify: ['🔍', '?'],
|
|
25
|
-
folder: ['📁', '[]'],
|
|
26
|
-
file: ['📄', '-'],
|
|
27
|
-
gear: ['⚙️', '@'],
|
|
28
|
-
lock: ['🔒', '#'],
|
|
29
|
-
key: ['🔑', '#'],
|
|
30
|
-
bulb: ['💡', '!'],
|
|
31
|
-
clock: ['⏰', 'T'],
|
|
32
|
-
success: ['✅', '[OK]'],
|
|
33
|
-
error: ['❌', '[ERR]'],
|
|
34
|
-
sparkle: ['✨', '*'],
|
|
35
|
-
chart: ['📊', '[=]'],
|
|
36
|
-
note: ['📝', '-'],
|
|
37
|
-
book: ['📚', '[]'],
|
|
38
|
-
package: ['📦', '[]'],
|
|
39
|
-
tools: ['🛠️', '[]'],
|
|
40
|
-
shield: ['🛡️', 'S'],
|
|
41
|
-
target: ['🎯', 'o'],
|
|
42
|
-
refresh: ['🔄', '@'],
|
|
43
|
-
lightning: ['⚡', '!'],
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Get appropriate icon for current environment
|
|
48
|
-
* @param {string} name - Icon name from ICONS map
|
|
49
|
-
* @returns {string} Unicode icon or ASCII fallback
|
|
50
|
-
*/
|
|
51
|
-
export function icon(name) {
|
|
52
|
-
const pair = ICONS[name];
|
|
53
|
-
if (!pair) return '';
|
|
54
|
-
return isWindowsConsole ? pair[1] : pair[0];
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Replace all emojis in text with ASCII equivalents
|
|
59
|
-
* @param {string} text - Text containing emojis
|
|
60
|
-
* @returns {string} Text with ASCII replacements on Windows
|
|
61
|
-
*/
|
|
62
|
-
export function safeText(text) {
|
|
63
|
-
if (!isWindowsConsole) return text;
|
|
64
|
-
|
|
65
|
-
let result = text;
|
|
66
|
-
for (const [name, [unicode, ascii]] of Object.entries(ICONS)) {
|
|
67
|
-
result = result.replace(new RegExp(unicode, 'g'), ascii);
|
|
68
|
-
}
|
|
69
|
-
return result;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Check if Unicode output is safe
|
|
74
|
-
* @returns {boolean}
|
|
75
|
-
*/
|
|
76
|
-
export function supportsUnicode() {
|
|
77
|
-
return !isWindowsConsole;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Quick accessor for common icons
|
|
81
|
-
export const icons = {
|
|
82
|
-
get brain() { return icon('brain'); },
|
|
83
|
-
get check() { return icon('check'); },
|
|
84
|
-
get cross() { return icon('cross'); },
|
|
85
|
-
get warning() { return icon('warning'); },
|
|
86
|
-
get arrow() { return icon('arrow'); },
|
|
87
|
-
get party() { return icon('party'); },
|
|
88
|
-
get success() { return icon('success'); },
|
|
89
|
-
get error() { return icon('error'); },
|
|
90
|
-
get sparkle() { return icon('sparkle'); },
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
export default { icon, safeText, supportsUnicode, icons, ICONS };
|