pikakit 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +239 -0
- package/bin/add-skill-kit.js +3 -0
- package/bin/cli.mjs +6 -0
- package/bin/kit.mjs +89 -0
- package/bin/lib/agents.js +208 -0
- package/bin/lib/commands/analyze.js +70 -0
- package/bin/lib/commands/cache.js +65 -0
- package/bin/lib/commands/doctor.js +75 -0
- package/bin/lib/commands/help.js +155 -0
- package/bin/lib/commands/info.js +38 -0
- package/bin/lib/commands/init.js +39 -0
- package/bin/lib/commands/install.js +803 -0
- package/bin/lib/commands/list.js +43 -0
- package/bin/lib/commands/lock.js +57 -0
- package/bin/lib/commands/uninstall.js +307 -0
- package/bin/lib/commands/update.js +55 -0
- package/bin/lib/commands/validate.js +69 -0
- package/bin/lib/commands/verify.js +56 -0
- package/bin/lib/config.js +81 -0
- package/bin/lib/helpers.js +196 -0
- package/bin/lib/helpers.test.js +60 -0
- package/bin/lib/installer.js +164 -0
- package/bin/lib/skills.js +119 -0
- package/bin/lib/skills.test.js +109 -0
- package/bin/lib/types.js +82 -0
- package/bin/lib/ui.js +329 -0
- package/lib/agent-cli/README.md +21 -0
- 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/backup.js +138 -0
- package/lib/agent-cli/lib/backup.test.js +78 -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/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/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/lib/agentskillskit-cli/ag-smart.js +158 -0
- package/lib/agentskillskit-cli/package.json +51 -0
- package/package.json +79 -0
- package/specs/ADD_SKILL_SPEC.md +333 -0
- package/specs/REGISTRY_V2_SPEC.md +334 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stats UI - Knowledge base statistics display
|
|
3
|
+
*/
|
|
4
|
+
import { ICONS, getKnowledge, line, VERSION } from "./common.js";
|
|
5
|
+
import { showIntro, showInfoNote, showSuccessNote, createSpinner, theme } from "./clack-helpers.js";
|
|
6
|
+
import { signalQueue, getEvolutionStats } from "../evolution-signal.js";
|
|
7
|
+
import * as p from "@clack/prompts";
|
|
8
|
+
import pc from "picocolors";
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// STATS DISPLAY
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Stats UI - Show knowledge base statistics with cognitive insights
|
|
16
|
+
*/
|
|
17
|
+
export async function runStatsUI() {
|
|
18
|
+
// Clear terminal và reset cursor về top-left
|
|
19
|
+
process.stdout.write('\x1Bc'); // Full terminal reset
|
|
20
|
+
|
|
21
|
+
showIntro("📊 Knowledge Base Stats");
|
|
22
|
+
|
|
23
|
+
const spinner = createSpinner("Loading statistics...");
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const db = getKnowledge();
|
|
27
|
+
const lessons = db.lessons || [];
|
|
28
|
+
|
|
29
|
+
// Calculate statistics with cognitive awareness
|
|
30
|
+
const totalLessons = lessons.length;
|
|
31
|
+
const mistakes = lessons.filter(l => l.type === 'mistake');
|
|
32
|
+
const improvements = lessons.filter(l => l.type === 'improvement');
|
|
33
|
+
|
|
34
|
+
// Cognitive grouping - Intent
|
|
35
|
+
const byIntent = lessons.reduce((acc, l) => {
|
|
36
|
+
const intent = l.intent || 'unknown';
|
|
37
|
+
acc[intent] = (acc[intent] || 0) + 1;
|
|
38
|
+
return acc;
|
|
39
|
+
}, {});
|
|
40
|
+
|
|
41
|
+
// Cognitive grouping - Pattern Type
|
|
42
|
+
const byPatternType = lessons.reduce((acc, l) => {
|
|
43
|
+
const type = l.patternType || 'general';
|
|
44
|
+
acc[type] = (acc[type] || 0) + 1;
|
|
45
|
+
return acc;
|
|
46
|
+
}, {});
|
|
47
|
+
|
|
48
|
+
// Cognitive grouping - Maturity
|
|
49
|
+
const byMaturity = lessons.reduce((acc, l) => {
|
|
50
|
+
const maturity = l.cognitive?.maturity || 'learning';
|
|
51
|
+
acc[maturity] = (acc[maturity] || 0) + 1;
|
|
52
|
+
return acc;
|
|
53
|
+
}, {});
|
|
54
|
+
|
|
55
|
+
// Top 5 by hit count
|
|
56
|
+
const topHits = lessons
|
|
57
|
+
.filter(p => p.hitCount && p.hitCount > 0)
|
|
58
|
+
.sort((a, b) => b.hitCount - a.hitCount)
|
|
59
|
+
.slice(0, 5);
|
|
60
|
+
|
|
61
|
+
spinner.stopSuccess("Stats loaded");
|
|
62
|
+
|
|
63
|
+
// Compact single-line display
|
|
64
|
+
console.log(`\n${pc.bold('📊 Knowledge Stats')} ${pc.dim(`(${totalLessons} lessons)`)}\n`);
|
|
65
|
+
|
|
66
|
+
console.log(
|
|
67
|
+
`${pc.red('●')} ${mistakes.length} Mistakes ` +
|
|
68
|
+
`${pc.green('●')} ${improvements.length} Improvements ` +
|
|
69
|
+
`${pc.dim('│')} ` +
|
|
70
|
+
`${pc.red('🛡️')} ${byIntent.prevent || 0} Prevent ` +
|
|
71
|
+
`${pc.yellow('⚠️')} ${byIntent.warn || 0} Warn ` +
|
|
72
|
+
`${pc.green('⚡')} ${byIntent.optimize || 0} Optimize\n`
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
console.log(
|
|
76
|
+
`${pc.dim('Types:')} ` +
|
|
77
|
+
`${byPatternType.security ? `🔒${byPatternType.security} ` : ''}` +
|
|
78
|
+
`${byPatternType.dependency ? `📦${byPatternType.dependency} ` : ''}` +
|
|
79
|
+
`${byPatternType.structure ? `🏗️${byPatternType.structure} ` : ''}` +
|
|
80
|
+
`${byPatternType.quality ? `✨${byPatternType.quality} ` : ''}` +
|
|
81
|
+
`${byPatternType.performance ? `⚡${byPatternType.performance} ` : ''}` +
|
|
82
|
+
`${byPatternType.general ? pc.dim(`📝${byPatternType.general}`) : ''}\n`
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
console.log(
|
|
86
|
+
`${pc.dim('Maturity:')} ` +
|
|
87
|
+
`${pc.green('✓')} ${byMaturity.stable || 0} Stable ` +
|
|
88
|
+
`${pc.cyan('📚')} ${byMaturity.learning || 0} Learning\n`
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
// Show top 3 hits in compact format
|
|
92
|
+
if (topHits.length > 0) {
|
|
93
|
+
console.log(`${pc.bold('🔥 Top Patterns')}`);
|
|
94
|
+
topHits.slice(0, 3).forEach((p, i) => {
|
|
95
|
+
console.log(` ${i + 1}. ${pc.dim(p.id)} ${pc.bold(p.hitCount)}×`);
|
|
96
|
+
});
|
|
97
|
+
console.log('');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Show signal queue summary
|
|
101
|
+
const signalStats = getEvolutionStats();
|
|
102
|
+
const pending = signalQueue.getPending();
|
|
103
|
+
|
|
104
|
+
console.log(`${pc.bold('📡 Signal Queue')}`);
|
|
105
|
+
console.log(
|
|
106
|
+
` ${pc.yellow('⏳')} ${signalStats.pending} Pending ` +
|
|
107
|
+
`${pc.green('✓')} ${signalStats.approved} Approved ` +
|
|
108
|
+
`${pc.red('✗')} ${signalStats.rejected} Rejected\n`
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
// User can choose next action
|
|
112
|
+
await p.select({
|
|
113
|
+
message: "What's next?",
|
|
114
|
+
options: [
|
|
115
|
+
{ value: "back", label: "← Back to Main Menu" }
|
|
116
|
+
]
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
} catch (error) {
|
|
120
|
+
spinner.stopError("Failed to load stats");
|
|
121
|
+
console.error(error);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Watch UI - Real-Time File Monitoring with Clack UI
|
|
3
|
+
*
|
|
4
|
+
* Watches for file changes and runs recall automatically.
|
|
5
|
+
* Uses @clack/prompts for consistent terminal UI.
|
|
6
|
+
*/
|
|
7
|
+
import * as p from "@clack/prompts";
|
|
8
|
+
import pc from "picocolors";
|
|
9
|
+
import fs from "fs";
|
|
10
|
+
import path from "path";
|
|
11
|
+
import { fileURLToPath } from "url";
|
|
12
|
+
import { dirname } from "path";
|
|
13
|
+
import { scanFile, loadKnowledge, saveKnowledge } from "../recall.js";
|
|
14
|
+
import { VERSION } from "../config.js";
|
|
15
|
+
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// CONFIGURATION
|
|
18
|
+
// ============================================================================
|
|
19
|
+
|
|
20
|
+
const WATCH_EXTENSIONS = [".js", ".ts", ".tsx", ".jsx", ".mjs"];
|
|
21
|
+
const DEBOUNCE_MS = 300;
|
|
22
|
+
const SKIP_DIRS = ["node_modules", ".git", "dist", "build", ".next", "coverage"];
|
|
23
|
+
|
|
24
|
+
// ============================================================================
|
|
25
|
+
// WATCHER CLASS
|
|
26
|
+
// ============================================================================
|
|
27
|
+
|
|
28
|
+
class SmartWatcher {
|
|
29
|
+
constructor(rootDir) {
|
|
30
|
+
this.rootDir = path.resolve(rootDir);
|
|
31
|
+
this.db = loadKnowledge();
|
|
32
|
+
this.debounceTimers = new Map();
|
|
33
|
+
this.watchers = [];
|
|
34
|
+
this.isRunning = false;
|
|
35
|
+
this.sessionStats = {
|
|
36
|
+
filesChecked: 0,
|
|
37
|
+
violationsFound: 0,
|
|
38
|
+
startTime: Date.now()
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Start watching
|
|
44
|
+
*/
|
|
45
|
+
start() {
|
|
46
|
+
this.isRunning = true;
|
|
47
|
+
this.watch(this.rootDir);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Stop watching
|
|
52
|
+
*/
|
|
53
|
+
stop() {
|
|
54
|
+
this.isRunning = false;
|
|
55
|
+
// Close all watchers
|
|
56
|
+
this.watchers.forEach(w => {
|
|
57
|
+
try { w.close(); } catch (e) { }
|
|
58
|
+
});
|
|
59
|
+
this.watchers = [];
|
|
60
|
+
// Clear debounce timers
|
|
61
|
+
this.debounceTimers.forEach(timer => clearTimeout(timer));
|
|
62
|
+
this.debounceTimers.clear();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Recursively watch directories
|
|
67
|
+
*/
|
|
68
|
+
watch(dir) {
|
|
69
|
+
try {
|
|
70
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
71
|
+
|
|
72
|
+
// Watch current directory
|
|
73
|
+
const watcher = fs.watch(dir, { persistent: true }, (eventType, filename) => {
|
|
74
|
+
if (filename && eventType === "change" && this.isRunning) {
|
|
75
|
+
this.handleChange(path.join(dir, filename));
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
this.watchers.push(watcher);
|
|
79
|
+
|
|
80
|
+
// Recurse into subdirs
|
|
81
|
+
for (const entry of entries) {
|
|
82
|
+
if (entry.isDirectory() && !SKIP_DIRS.includes(entry.name)) {
|
|
83
|
+
this.watch(path.join(dir, entry.name));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
} catch (error) {
|
|
87
|
+
// Ignore permission errors
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Handle file change with debouncing
|
|
93
|
+
*/
|
|
94
|
+
handleChange(filePath) {
|
|
95
|
+
const ext = path.extname(filePath);
|
|
96
|
+
if (!WATCH_EXTENSIONS.includes(ext)) return;
|
|
97
|
+
if (!fs.existsSync(filePath)) return;
|
|
98
|
+
|
|
99
|
+
// Debounce
|
|
100
|
+
if (this.debounceTimers.has(filePath)) {
|
|
101
|
+
clearTimeout(this.debounceTimers.get(filePath));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
this.debounceTimers.set(filePath, setTimeout(() => {
|
|
105
|
+
const result = this.checkFile(filePath);
|
|
106
|
+
this.debounceTimers.delete(filePath);
|
|
107
|
+
|
|
108
|
+
// Emit event for UI
|
|
109
|
+
if (this.onFileChange) {
|
|
110
|
+
this.onFileChange(result);
|
|
111
|
+
}
|
|
112
|
+
}, DEBOUNCE_MS));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Check a file against memory
|
|
117
|
+
*/
|
|
118
|
+
checkFile(filePath) {
|
|
119
|
+
const relativePath = path.relative(this.rootDir, filePath);
|
|
120
|
+
const result = scanFile(filePath, this.db, true);
|
|
121
|
+
|
|
122
|
+
this.sessionStats.filesChecked++;
|
|
123
|
+
|
|
124
|
+
if (result.violations.length > 0) {
|
|
125
|
+
this.sessionStats.violationsFound += result.violations.reduce((sum, v) => sum + v.matches.length, 0);
|
|
126
|
+
saveKnowledge(this.db);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
path: relativePath,
|
|
131
|
+
violations: result.violations,
|
|
132
|
+
hasViolations: result.violations.length > 0
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Get session summary
|
|
138
|
+
*/
|
|
139
|
+
getSummary() {
|
|
140
|
+
const duration = Math.round((Date.now() - this.sessionStats.startTime) / 1000);
|
|
141
|
+
return {
|
|
142
|
+
duration,
|
|
143
|
+
filesChecked: this.sessionStats.filesChecked,
|
|
144
|
+
violationsFound: this.sessionStats.violationsFound
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ============================================================================
|
|
150
|
+
// WATCH UI
|
|
151
|
+
// ============================================================================
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Run Watch UI with Clack
|
|
155
|
+
* @param {string} targetDir - Directory to watch
|
|
156
|
+
*/
|
|
157
|
+
export async function runWatchUI(targetDir = process.cwd()) {
|
|
158
|
+
const watcher = new SmartWatcher(targetDir);
|
|
159
|
+
|
|
160
|
+
// Show intro
|
|
161
|
+
p.intro(pc.cyan(`Smart Watcher v${VERSION}`));
|
|
162
|
+
|
|
163
|
+
// Show info
|
|
164
|
+
p.note(
|
|
165
|
+
`${pc.dim("Directory:")} ${watcher.rootDir}\n` +
|
|
166
|
+
`${pc.dim("Patterns:")} ${watcher.db.lessons.length} loaded\n` +
|
|
167
|
+
`${pc.dim("Extensions:")} ${WATCH_EXTENSIONS.join(", ")}`,
|
|
168
|
+
"Watch Configuration"
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
// Spinner for starting
|
|
172
|
+
const s = p.spinner();
|
|
173
|
+
s.start("Starting file watcher...");
|
|
174
|
+
|
|
175
|
+
// Start watcher
|
|
176
|
+
watcher.start();
|
|
177
|
+
|
|
178
|
+
s.stop(pc.green("✓") + " Watching for changes");
|
|
179
|
+
|
|
180
|
+
// Setup file change handler
|
|
181
|
+
watcher.onFileChange = (result) => {
|
|
182
|
+
if (result.hasViolations) {
|
|
183
|
+
console.log("");
|
|
184
|
+
p.log.warn(pc.yellow(result.path));
|
|
185
|
+
result.violations.forEach(({ lesson, matches }) => {
|
|
186
|
+
const icon = lesson.severity === "ERROR" ? pc.red("✖") : pc.yellow("⚠");
|
|
187
|
+
console.log(` ${icon} ${pc.dim(`[${lesson.id}]`)} ${lesson.message}`);
|
|
188
|
+
matches.slice(0, 2).forEach(m => {
|
|
189
|
+
console.log(` ${pc.dim(`L${m.line}:`)} ${pc.dim(m.content.substring(0, 60))}`);
|
|
190
|
+
});
|
|
191
|
+
if (matches.length > 2) {
|
|
192
|
+
console.log(` ${pc.dim(`... +${matches.length - 2} more`)}`);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
} else {
|
|
196
|
+
p.log.success(pc.green("✓ ") + pc.dim(result.path));
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// Wait for user to press Enter or Ctrl+C
|
|
201
|
+
console.log("");
|
|
202
|
+
console.log(pc.dim(" Watching for file changes..."));
|
|
203
|
+
console.log(pc.dim(" Press Enter to stop\n"));
|
|
204
|
+
|
|
205
|
+
// Wait for Enter key
|
|
206
|
+
await new Promise((resolve) => {
|
|
207
|
+
const handler = (data) => {
|
|
208
|
+
if (data.toString().includes("\n") || data.toString().includes("\r")) {
|
|
209
|
+
process.stdin.removeListener("data", handler);
|
|
210
|
+
process.stdin.setRawMode?.(false);
|
|
211
|
+
resolve();
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
process.stdin.setRawMode?.(true);
|
|
216
|
+
process.stdin.resume();
|
|
217
|
+
process.stdin.on("data", handler);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// Stop watcher
|
|
221
|
+
watcher.stop();
|
|
222
|
+
|
|
223
|
+
// Show summary
|
|
224
|
+
const summary = watcher.getSummary();
|
|
225
|
+
|
|
226
|
+
p.note(
|
|
227
|
+
`${pc.dim("Duration:")} ${summary.duration}s\n` +
|
|
228
|
+
`${pc.dim("Files:")} ${summary.filesChecked} checked\n` +
|
|
229
|
+
`${pc.dim("Violations:")} ${summary.violationsFound} found`,
|
|
230
|
+
"Session Summary"
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
p.outro(pc.green("Watch session ended"));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export default runWatchUI;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Smart Watcher - Real-Time File Monitoring
|
|
4
|
+
*
|
|
5
|
+
* Watches for file changes and runs recall automatically.
|
|
6
|
+
* Features:
|
|
7
|
+
* - Debounced file change detection
|
|
8
|
+
* - Pattern frequency tracking
|
|
9
|
+
* - Live feedback on violations
|
|
10
|
+
*
|
|
11
|
+
* Usage: agent watch [directory]
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import fs from "fs";
|
|
15
|
+
import path from "path";
|
|
16
|
+
import { scanFile, loadKnowledge, saveKnowledge } from "./recall.js";
|
|
17
|
+
import { VERSION } from "./config.js";
|
|
18
|
+
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// CONFIGURATION
|
|
21
|
+
// ============================================================================
|
|
22
|
+
|
|
23
|
+
const WATCH_EXTENSIONS = [".js", ".ts", ".tsx", ".jsx", ".mjs"];
|
|
24
|
+
const DEBOUNCE_MS = 300;
|
|
25
|
+
const SKIP_DIRS = ["node_modules", ".git", "dist", "build", ".next", "coverage"];
|
|
26
|
+
|
|
27
|
+
// ============================================================================
|
|
28
|
+
// WATCHER
|
|
29
|
+
// ============================================================================
|
|
30
|
+
|
|
31
|
+
class SmartWatcher {
|
|
32
|
+
constructor(rootDir) {
|
|
33
|
+
this.rootDir = path.resolve(rootDir);
|
|
34
|
+
this.db = loadKnowledge();
|
|
35
|
+
this.debounceTimers = new Map();
|
|
36
|
+
this.sessionStats = {
|
|
37
|
+
filesChecked: 0,
|
|
38
|
+
violationsFound: 0,
|
|
39
|
+
startTime: Date.now()
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Start watching
|
|
45
|
+
*/
|
|
46
|
+
start() {
|
|
47
|
+
console.log(`\n👁️ Smart Watcher v${VERSION}`);
|
|
48
|
+
console.log(`📂 Watching: ${this.rootDir}`);
|
|
49
|
+
console.log(`📚 Loaded ${this.db.lessons.length} pattern(s) from memory`);
|
|
50
|
+
console.log("─".repeat(50));
|
|
51
|
+
console.log("Watching for changes... (Ctrl+C to stop)\n");
|
|
52
|
+
|
|
53
|
+
this.watch(this.rootDir);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Recursively watch directories
|
|
58
|
+
*/
|
|
59
|
+
watch(dir) {
|
|
60
|
+
try {
|
|
61
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
62
|
+
|
|
63
|
+
// Watch current directory
|
|
64
|
+
fs.watch(dir, { persistent: true }, (eventType, filename) => {
|
|
65
|
+
if (filename && eventType === "change") {
|
|
66
|
+
this.handleChange(path.join(dir, filename));
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Recurse into subdirs
|
|
71
|
+
for (const entry of entries) {
|
|
72
|
+
if (entry.isDirectory() && !SKIP_DIRS.includes(entry.name)) {
|
|
73
|
+
this.watch(path.join(dir, entry.name));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
} catch (error) {
|
|
77
|
+
// Ignore permission errors
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Handle file change with debouncing
|
|
83
|
+
*/
|
|
84
|
+
handleChange(filePath) {
|
|
85
|
+
const ext = path.extname(filePath);
|
|
86
|
+
if (!WATCH_EXTENSIONS.includes(ext)) return;
|
|
87
|
+
if (!fs.existsSync(filePath)) return;
|
|
88
|
+
|
|
89
|
+
// Debounce
|
|
90
|
+
if (this.debounceTimers.has(filePath)) {
|
|
91
|
+
clearTimeout(this.debounceTimers.get(filePath));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
this.debounceTimers.set(filePath, setTimeout(() => {
|
|
95
|
+
this.checkFile(filePath);
|
|
96
|
+
this.debounceTimers.delete(filePath);
|
|
97
|
+
}, DEBOUNCE_MS));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Check a file against memory
|
|
102
|
+
*/
|
|
103
|
+
checkFile(filePath) {
|
|
104
|
+
const relativePath = path.relative(this.rootDir, filePath);
|
|
105
|
+
const result = scanFile(filePath, this.db, true);
|
|
106
|
+
|
|
107
|
+
this.sessionStats.filesChecked++;
|
|
108
|
+
|
|
109
|
+
if (result.violations.length === 0) {
|
|
110
|
+
console.log(`✅ ${relativePath}`);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
console.log(`\n⚠️ ${relativePath}`);
|
|
115
|
+
|
|
116
|
+
result.violations.forEach(({ lesson, matches }) => {
|
|
117
|
+
this.sessionStats.violationsFound += matches.length;
|
|
118
|
+
|
|
119
|
+
const icon = lesson.severity === "ERROR" ? "❌" : "⚠️";
|
|
120
|
+
console.log(` ${icon} [${lesson.id}] ${lesson.message}`);
|
|
121
|
+
|
|
122
|
+
matches.slice(0, 3).forEach(m => {
|
|
123
|
+
console.log(` L${m.line}: ${m.content}`);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
if (matches.length > 3) {
|
|
127
|
+
console.log(` ... and ${matches.length - 3} more`);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
console.log("");
|
|
132
|
+
|
|
133
|
+
// Save updated stats
|
|
134
|
+
saveKnowledge(this.db);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Print session summary
|
|
139
|
+
*/
|
|
140
|
+
printSummary() {
|
|
141
|
+
const duration = Math.round((Date.now() - this.sessionStats.startTime) / 1000);
|
|
142
|
+
console.log("\n" + "─".repeat(50));
|
|
143
|
+
console.log("📊 Session Summary:");
|
|
144
|
+
console.log(` ⏱️ Duration: ${duration}s`);
|
|
145
|
+
console.log(` 📄 Files checked: ${this.sessionStats.filesChecked}`);
|
|
146
|
+
console.log(` ⚠️ Violations found: ${this.sessionStats.violationsFound}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ============================================================================
|
|
151
|
+
// CLI
|
|
152
|
+
// ============================================================================
|
|
153
|
+
|
|
154
|
+
const args = process.argv.slice(2);
|
|
155
|
+
const targetDir = args[0] || process.cwd();
|
|
156
|
+
|
|
157
|
+
if (args.includes("--help")) {
|
|
158
|
+
console.log(`
|
|
159
|
+
👁️ Smart Watcher - Real-Time Monitor
|
|
160
|
+
|
|
161
|
+
Usage:
|
|
162
|
+
agent watch [directory]
|
|
163
|
+
|
|
164
|
+
Options:
|
|
165
|
+
--help Show this help
|
|
166
|
+
|
|
167
|
+
The watcher monitors file changes and checks them against
|
|
168
|
+
learned patterns in real-time.
|
|
169
|
+
`);
|
|
170
|
+
process.exit(0);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const watcher = new SmartWatcher(targetDir);
|
|
174
|
+
|
|
175
|
+
// Handle graceful shutdown
|
|
176
|
+
process.on("SIGINT", () => {
|
|
177
|
+
watcher.printSummary();
|
|
178
|
+
process.exit(0);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
watcher.start();
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Tests for watcher.js functionality
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it, expect } from "vitest";
|
|
5
|
+
import path from "path";
|
|
6
|
+
|
|
7
|
+
describe("Watcher - Extension Filtering", () => {
|
|
8
|
+
const WATCH_EXTENSIONS = [".js", ".ts", ".tsx", ".jsx", ".mjs"];
|
|
9
|
+
|
|
10
|
+
it("includes JavaScript files", () => {
|
|
11
|
+
const file = "app.js";
|
|
12
|
+
const ext = path.extname(file);
|
|
13
|
+
expect(WATCH_EXTENSIONS.includes(ext)).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("includes TypeScript files", () => {
|
|
17
|
+
const file = "app.tsx";
|
|
18
|
+
const ext = path.extname(file);
|
|
19
|
+
expect(WATCH_EXTENSIONS.includes(ext)).toBe(true);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("excludes CSS files", () => {
|
|
23
|
+
const file = "styles.css";
|
|
24
|
+
const ext = path.extname(file);
|
|
25
|
+
expect(WATCH_EXTENSIONS.includes(ext)).toBe(false);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("excludes markdown files", () => {
|
|
29
|
+
const file = "README.md";
|
|
30
|
+
const ext = path.extname(file);
|
|
31
|
+
expect(WATCH_EXTENSIONS.includes(ext)).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe("Watcher - Directory Filtering", () => {
|
|
36
|
+
const SKIP_DIRS = ["node_modules", ".git", "dist", "build", ".next", "coverage"];
|
|
37
|
+
|
|
38
|
+
it("skips node_modules", () => {
|
|
39
|
+
expect(SKIP_DIRS.includes("node_modules")).toBe(true);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("skips .git directory", () => {
|
|
43
|
+
expect(SKIP_DIRS.includes(".git")).toBe(true);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("skips dist directory", () => {
|
|
47
|
+
expect(SKIP_DIRS.includes("dist")).toBe(true);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("allows src directory", () => {
|
|
51
|
+
expect(SKIP_DIRS.includes("src")).toBe(false);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("allows lib directory", () => {
|
|
55
|
+
expect(SKIP_DIRS.includes("lib")).toBe(false);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe("Watcher - Session Stats", () => {
|
|
60
|
+
it("initializes session stats correctly", () => {
|
|
61
|
+
const sessionStats = {
|
|
62
|
+
filesChecked: 0,
|
|
63
|
+
violationsFound: 0,
|
|
64
|
+
startTime: Date.now()
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
expect(sessionStats.filesChecked).toBe(0);
|
|
68
|
+
expect(sessionStats.violationsFound).toBe(0);
|
|
69
|
+
expect(typeof sessionStats.startTime).toBe("number");
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("increments file count correctly", () => {
|
|
73
|
+
const sessionStats = { filesChecked: 0 };
|
|
74
|
+
sessionStats.filesChecked++;
|
|
75
|
+
sessionStats.filesChecked++;
|
|
76
|
+
expect(sessionStats.filesChecked).toBe(2);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("calculates duration correctly", () => {
|
|
80
|
+
const startTime = Date.now() - 5000; // 5 seconds ago
|
|
81
|
+
const duration = Math.round((Date.now() - startTime) / 1000);
|
|
82
|
+
expect(duration).toBeGreaterThanOrEqual(4);
|
|
83
|
+
expect(duration).toBeLessThanOrEqual(6);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agentskillskit-cli",
|
|
3
|
+
"version": "3.2.4",
|
|
4
|
+
"description": "CLI for Agent Skill Kit",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "lib/config.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"agent": "bin/agent.js",
|
|
9
|
+
"agent": "bin/agent.js",
|
|
10
|
+
"agent-skills-kit": "bin/agent.js"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"test": "vitest run",
|
|
14
|
+
"test:watch": "vitest"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@clack/core": "^0.5.0",
|
|
18
|
+
"@clack/prompts": "^0.11.0",
|
|
19
|
+
"boxen": "^8.0.1",
|
|
20
|
+
"clipboardy": "^5.1.0",
|
|
21
|
+
"js-yaml": "^4.1.0",
|
|
22
|
+
"ora": "^9.1.0",
|
|
23
|
+
"picocolors": "^1.1.1"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"vitest": "^1.6.0"
|
|
27
|
+
},
|
|
28
|
+
"author": "Agent Skill Kit Authors",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/agentskillkit/agent-skills.git",
|
|
33
|
+
"directory": "packages/cli"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"agent",
|
|
37
|
+
"ai",
|
|
38
|
+
"skills",
|
|
39
|
+
"cli",
|
|
40
|
+
"tooling",
|
|
41
|
+
"antigravity"
|
|
42
|
+
],
|
|
43
|
+
"files": [
|
|
44
|
+
"bin",
|
|
45
|
+
"lib",
|
|
46
|
+
"README.md"
|
|
47
|
+
],
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"access": "public"
|
|
50
|
+
}
|
|
51
|
+
}
|