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.
Files changed (145) hide show
  1. package/README.md +239 -0
  2. package/bin/add-skill-kit.js +3 -0
  3. package/bin/cli.mjs +6 -0
  4. package/bin/kit.mjs +89 -0
  5. package/bin/lib/agents.js +208 -0
  6. package/bin/lib/commands/analyze.js +70 -0
  7. package/bin/lib/commands/cache.js +65 -0
  8. package/bin/lib/commands/doctor.js +75 -0
  9. package/bin/lib/commands/help.js +155 -0
  10. package/bin/lib/commands/info.js +38 -0
  11. package/bin/lib/commands/init.js +39 -0
  12. package/bin/lib/commands/install.js +803 -0
  13. package/bin/lib/commands/list.js +43 -0
  14. package/bin/lib/commands/lock.js +57 -0
  15. package/bin/lib/commands/uninstall.js +307 -0
  16. package/bin/lib/commands/update.js +55 -0
  17. package/bin/lib/commands/validate.js +69 -0
  18. package/bin/lib/commands/verify.js +56 -0
  19. package/bin/lib/config.js +81 -0
  20. package/bin/lib/helpers.js +196 -0
  21. package/bin/lib/helpers.test.js +60 -0
  22. package/bin/lib/installer.js +164 -0
  23. package/bin/lib/skills.js +119 -0
  24. package/bin/lib/skills.test.js +109 -0
  25. package/bin/lib/types.js +82 -0
  26. package/bin/lib/ui.js +329 -0
  27. package/lib/agent-cli/README.md +21 -0
  28. package/lib/agent-cli/__tests__/adaptive_engine.test.js +190 -0
  29. package/lib/agent-cli/__tests__/integration/cross_script.test.js +222 -0
  30. package/lib/agent-cli/__tests__/integration/full_cycle.test.js +230 -0
  31. package/lib/agent-cli/__tests__/pattern_analyzer.test.js +173 -0
  32. package/lib/agent-cli/__tests__/pre_execution_check.test.js +167 -0
  33. package/lib/agent-cli/__tests__/skill_injector.test.js +191 -0
  34. package/lib/agent-cli/bin/agent.js +191 -0
  35. package/lib/agent-cli/dashboard/dashboard_server.js +340 -0
  36. package/lib/agent-cli/dashboard/index.html +538 -0
  37. package/lib/agent-cli/lib/audit.js +154 -0
  38. package/lib/agent-cli/lib/audit.test.js +100 -0
  39. package/lib/agent-cli/lib/auto-learn.js +319 -0
  40. package/lib/agent-cli/lib/backup.js +138 -0
  41. package/lib/agent-cli/lib/backup.test.js +78 -0
  42. package/lib/agent-cli/lib/cognitive-lesson.js +476 -0
  43. package/lib/agent-cli/lib/completion.js +149 -0
  44. package/lib/agent-cli/lib/config.js +35 -0
  45. package/lib/agent-cli/lib/eslint-fix.js +238 -0
  46. package/lib/agent-cli/lib/evolution-signal.js +215 -0
  47. package/lib/agent-cli/lib/export.js +86 -0
  48. package/lib/agent-cli/lib/export.test.js +65 -0
  49. package/lib/agent-cli/lib/fix.js +337 -0
  50. package/lib/agent-cli/lib/fix.test.js +80 -0
  51. package/lib/agent-cli/lib/gemini-export.js +83 -0
  52. package/lib/agent-cli/lib/generate-registry.js +42 -0
  53. package/lib/agent-cli/lib/hooks/install-hooks.js +152 -0
  54. package/lib/agent-cli/lib/hooks/lint-learn.js +172 -0
  55. package/lib/agent-cli/lib/ignore.js +116 -0
  56. package/lib/agent-cli/lib/ignore.test.js +58 -0
  57. package/lib/agent-cli/lib/init.js +124 -0
  58. package/lib/agent-cli/lib/learn.js +255 -0
  59. package/lib/agent-cli/lib/learn.test.js +70 -0
  60. package/lib/agent-cli/lib/migrate-to-v4.js +322 -0
  61. package/lib/agent-cli/lib/proposals.js +199 -0
  62. package/lib/agent-cli/lib/proposals.test.js +56 -0
  63. package/lib/agent-cli/lib/recall.js +820 -0
  64. package/lib/agent-cli/lib/recall.test.js +107 -0
  65. package/lib/agent-cli/lib/selfevolution-bridge.js +167 -0
  66. package/lib/agent-cli/lib/settings.js +227 -0
  67. package/lib/agent-cli/lib/skill-learn.js +296 -0
  68. package/lib/agent-cli/lib/stats.js +132 -0
  69. package/lib/agent-cli/lib/stats.test.js +94 -0
  70. package/lib/agent-cli/lib/types.js +33 -0
  71. package/lib/agent-cli/lib/ui/audit-ui.js +146 -0
  72. package/lib/agent-cli/lib/ui/backup-ui.js +107 -0
  73. package/lib/agent-cli/lib/ui/clack-helpers.js +317 -0
  74. package/lib/agent-cli/lib/ui/common.js +83 -0
  75. package/lib/agent-cli/lib/ui/completion-ui.js +126 -0
  76. package/lib/agent-cli/lib/ui/custom-select.js +69 -0
  77. package/lib/agent-cli/lib/ui/dashboard-ui.js +222 -0
  78. package/lib/agent-cli/lib/ui/evolution-signals-ui.js +107 -0
  79. package/lib/agent-cli/lib/ui/export-ui.js +94 -0
  80. package/lib/agent-cli/lib/ui/fix-all-ui.js +191 -0
  81. package/lib/agent-cli/lib/ui/help-ui.js +49 -0
  82. package/lib/agent-cli/lib/ui/index.js +199 -0
  83. package/lib/agent-cli/lib/ui/init-ui.js +56 -0
  84. package/lib/agent-cli/lib/ui/knowledge-ui.js +55 -0
  85. package/lib/agent-cli/lib/ui/learn-ui.js +706 -0
  86. package/lib/agent-cli/lib/ui/lessons-ui.js +148 -0
  87. package/lib/agent-cli/lib/ui/pretty.js +145 -0
  88. package/lib/agent-cli/lib/ui/proposals-ui.js +99 -0
  89. package/lib/agent-cli/lib/ui/recall-ui.js +342 -0
  90. package/lib/agent-cli/lib/ui/routing-demo.js +79 -0
  91. package/lib/agent-cli/lib/ui/routing-ui.js +325 -0
  92. package/lib/agent-cli/lib/ui/settings-ui.js +381 -0
  93. package/lib/agent-cli/lib/ui/stats-ui.js +123 -0
  94. package/lib/agent-cli/lib/ui/watch-ui.js +236 -0
  95. package/lib/agent-cli/lib/watcher.js +181 -0
  96. package/lib/agent-cli/lib/watcher.test.js +85 -0
  97. package/lib/agent-cli/package.json +51 -0
  98. package/lib/agent-cli/scripts/adaptive_engine.js +381 -0
  99. package/lib/agent-cli/scripts/dashboard_server.js +224 -0
  100. package/lib/agent-cli/scripts/error_sensor.js +565 -0
  101. package/lib/agent-cli/scripts/learn_from_failure.js +225 -0
  102. package/lib/agent-cli/scripts/pattern_analyzer.js +781 -0
  103. package/lib/agent-cli/scripts/pre_execution_check.js +623 -0
  104. package/lib/agent-cli/scripts/rule_sharing.js +374 -0
  105. package/lib/agent-cli/scripts/skill_injector.js +387 -0
  106. package/lib/agent-cli/scripts/success_sensor.js +500 -0
  107. package/lib/agent-cli/scripts/user_correction_sensor.js +426 -0
  108. package/lib/agent-cli/services/auto-learn-service.js +247 -0
  109. package/lib/agent-cli/src/MIGRATION.md +418 -0
  110. package/lib/agent-cli/src/README.md +367 -0
  111. package/lib/agent-cli/src/core/evolution/evolution-signal.js +42 -0
  112. package/lib/agent-cli/src/core/evolution/index.js +17 -0
  113. package/lib/agent-cli/src/core/evolution/review-gate.js +40 -0
  114. package/lib/agent-cli/src/core/evolution/signal-detector.js +137 -0
  115. package/lib/agent-cli/src/core/evolution/signal-queue.js +79 -0
  116. package/lib/agent-cli/src/core/evolution/threshold-checker.js +79 -0
  117. package/lib/agent-cli/src/core/index.js +15 -0
  118. package/lib/agent-cli/src/core/learning/cognitive-enhancer.js +282 -0
  119. package/lib/agent-cli/src/core/learning/index.js +12 -0
  120. package/lib/agent-cli/src/core/learning/lesson-synthesizer.js +83 -0
  121. package/lib/agent-cli/src/core/scanning/index.js +14 -0
  122. package/lib/agent-cli/src/data/index.js +13 -0
  123. package/lib/agent-cli/src/data/repositories/index.js +8 -0
  124. package/lib/agent-cli/src/data/repositories/lesson-repository.js +130 -0
  125. package/lib/agent-cli/src/data/repositories/signal-repository.js +119 -0
  126. package/lib/agent-cli/src/data/storage/index.js +8 -0
  127. package/lib/agent-cli/src/data/storage/json-storage.js +64 -0
  128. package/lib/agent-cli/src/data/storage/yaml-storage.js +66 -0
  129. package/lib/agent-cli/src/infrastructure/index.js +13 -0
  130. package/lib/agent-cli/src/presentation/formatters/skill-formatter.js +232 -0
  131. package/lib/agent-cli/src/services/export-service.js +162 -0
  132. package/lib/agent-cli/src/services/index.js +13 -0
  133. package/lib/agent-cli/src/services/learning-service.js +99 -0
  134. package/lib/agent-cli/types/index.d.ts +343 -0
  135. package/lib/agent-cli/utils/benchmark.js +269 -0
  136. package/lib/agent-cli/utils/logger.js +303 -0
  137. package/lib/agent-cli/utils/ml_patterns.js +300 -0
  138. package/lib/agent-cli/utils/recovery.js +312 -0
  139. package/lib/agent-cli/utils/telemetry.js +290 -0
  140. package/lib/agentskillskit-cli/README.md +21 -0
  141. package/lib/agentskillskit-cli/ag-smart.js +158 -0
  142. package/lib/agentskillskit-cli/package.json +51 -0
  143. package/package.json +79 -0
  144. package/specs/ADD_SKILL_SPEC.md +333 -0
  145. 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
+ }