pikakit 3.0.5 → 3.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +1 -1
  2. package/bin/lib/commands/install.js +119 -242
  3. package/package.json +3 -4
  4. package/lib/agent-cli/bin/agent.js +0 -187
  5. package/lib/agent-cli/dashboard/dashboard_server.js +0 -312
  6. package/lib/agent-cli/lib/ab-testing.js +0 -364
  7. package/lib/agent-cli/lib/audit.js +0 -154
  8. package/lib/agent-cli/lib/audit.test.js +0 -100
  9. package/lib/agent-cli/lib/auto-learn.js +0 -319
  10. package/lib/agent-cli/lib/backup.js +0 -138
  11. package/lib/agent-cli/lib/backup.test.js +0 -78
  12. package/lib/agent-cli/lib/causality-engine.js +0 -331
  13. package/lib/agent-cli/lib/cognitive-lesson.js +0 -476
  14. package/lib/agent-cli/lib/completion.js +0 -149
  15. package/lib/agent-cli/lib/config.js +0 -35
  16. package/lib/agent-cli/lib/dashboard-data.js +0 -380
  17. package/lib/agent-cli/lib/eslint-fix.js +0 -238
  18. package/lib/agent-cli/lib/evolution-signal.js +0 -215
  19. package/lib/agent-cli/lib/export.js +0 -86
  20. package/lib/agent-cli/lib/export.test.js +0 -65
  21. package/lib/agent-cli/lib/fix.js +0 -337
  22. package/lib/agent-cli/lib/fix.test.js +0 -80
  23. package/lib/agent-cli/lib/gemini-export.js +0 -83
  24. package/lib/agent-cli/lib/generate-registry.js +0 -42
  25. package/lib/agent-cli/lib/hooks/install-hooks.js +0 -152
  26. package/lib/agent-cli/lib/hooks/lint-learn.js +0 -172
  27. package/lib/agent-cli/lib/icons.js +0 -93
  28. package/lib/agent-cli/lib/ignore.js +0 -116
  29. package/lib/agent-cli/lib/ignore.test.js +0 -58
  30. package/lib/agent-cli/lib/init.js +0 -124
  31. package/lib/agent-cli/lib/knowledge-index.js +0 -326
  32. package/lib/agent-cli/lib/knowledge-metrics.js +0 -335
  33. package/lib/agent-cli/lib/knowledge-retention.js +0 -398
  34. package/lib/agent-cli/lib/knowledge-validator.js +0 -312
  35. package/lib/agent-cli/lib/learn.js +0 -255
  36. package/lib/agent-cli/lib/learn.test.js +0 -70
  37. package/lib/agent-cli/lib/metrics-collector.js +0 -410
  38. package/lib/agent-cli/lib/proposals.js +0 -199
  39. package/lib/agent-cli/lib/proposals.test.js +0 -56
  40. package/lib/agent-cli/lib/recall.js +0 -835
  41. package/lib/agent-cli/lib/recall.test.js +0 -107
  42. package/lib/agent-cli/lib/reinforcement.js +0 -299
  43. package/lib/agent-cli/lib/selfevolution-bridge.js +0 -167
  44. package/lib/agent-cli/lib/settings.js +0 -203
  45. package/lib/agent-cli/lib/skill-generator.js +0 -379
  46. package/lib/agent-cli/lib/skill-learn.js +0 -296
  47. package/lib/agent-cli/lib/stats.js +0 -132
  48. package/lib/agent-cli/lib/stats.test.js +0 -94
  49. package/lib/agent-cli/lib/types.js +0 -33
  50. package/lib/agent-cli/lib/ui/audit-ui.js +0 -146
  51. package/lib/agent-cli/lib/ui/backup-ui.js +0 -107
  52. package/lib/agent-cli/lib/ui/clack-helpers.js +0 -317
  53. package/lib/agent-cli/lib/ui/common.js +0 -83
  54. package/lib/agent-cli/lib/ui/completion-ui.js +0 -126
  55. package/lib/agent-cli/lib/ui/custom-select.js +0 -69
  56. package/lib/agent-cli/lib/ui/dashboard-ui.js +0 -222
  57. package/lib/agent-cli/lib/ui/evolution-signals-ui.js +0 -107
  58. package/lib/agent-cli/lib/ui/export-ui.js +0 -94
  59. package/lib/agent-cli/lib/ui/fix-all-ui.js +0 -191
  60. package/lib/agent-cli/lib/ui/help-ui.js +0 -49
  61. package/lib/agent-cli/lib/ui/index.js +0 -199
  62. package/lib/agent-cli/lib/ui/init-ui.js +0 -56
  63. package/lib/agent-cli/lib/ui/knowledge-ui.js +0 -55
  64. package/lib/agent-cli/lib/ui/learn-ui.js +0 -706
  65. package/lib/agent-cli/lib/ui/lessons-ui.js +0 -148
  66. package/lib/agent-cli/lib/ui/pretty.js +0 -145
  67. package/lib/agent-cli/lib/ui/proposals-ui.js +0 -99
  68. package/lib/agent-cli/lib/ui/recall-ui.js +0 -342
  69. package/lib/agent-cli/lib/ui/routing-demo.js +0 -79
  70. package/lib/agent-cli/lib/ui/routing-ui.js +0 -325
  71. package/lib/agent-cli/lib/ui/settings-ui.js +0 -381
  72. package/lib/agent-cli/lib/ui/stats-ui.js +0 -123
  73. package/lib/agent-cli/lib/ui/watch-ui.js +0 -236
  74. package/lib/agent-cli/lib/watcher.js +0 -181
  75. package/lib/agent-cli/lib/watcher.test.js +0 -85
  76. package/lib/agent-cli/src/MIGRATION.md +0 -418
  77. package/lib/agent-cli/src/README.md +0 -367
  78. package/lib/agent-cli/src/core/evolution/evolution-signal.js +0 -42
  79. package/lib/agent-cli/src/core/evolution/index.js +0 -17
  80. package/lib/agent-cli/src/core/evolution/review-gate.js +0 -40
  81. package/lib/agent-cli/src/core/evolution/signal-detector.js +0 -137
  82. package/lib/agent-cli/src/core/evolution/signal-queue.js +0 -79
  83. package/lib/agent-cli/src/core/evolution/threshold-checker.js +0 -79
  84. package/lib/agent-cli/src/core/index.js +0 -15
  85. package/lib/agent-cli/src/core/learning/cognitive-enhancer.js +0 -282
  86. package/lib/agent-cli/src/core/learning/index.js +0 -12
  87. package/lib/agent-cli/src/core/learning/lesson-synthesizer.js +0 -83
  88. package/lib/agent-cli/src/core/scanning/index.js +0 -14
  89. package/lib/agent-cli/src/data/index.js +0 -13
  90. package/lib/agent-cli/src/data/repositories/index.js +0 -8
  91. package/lib/agent-cli/src/data/repositories/lesson-repository.js +0 -130
  92. package/lib/agent-cli/src/data/repositories/signal-repository.js +0 -119
  93. package/lib/agent-cli/src/data/storage/index.js +0 -8
  94. package/lib/agent-cli/src/data/storage/json-storage.js +0 -64
  95. package/lib/agent-cli/src/data/storage/yaml-storage.js +0 -66
  96. package/lib/agent-cli/src/infrastructure/index.js +0 -13
  97. package/lib/agent-cli/src/presentation/formatters/skill-formatter.js +0 -232
  98. package/lib/agent-cli/src/services/export-service.js +0 -162
  99. package/lib/agent-cli/src/services/index.js +0 -13
  100. package/lib/agent-cli/src/services/learning-service.js +0 -99
@@ -1,215 +0,0 @@
1
- /**
2
- * Evolution Signal Layer - Backward Compatibility Adapter
3
- *
4
- * This file maintains the old API while delegating to the new architecture.
5
- * Allows gradual migration without breaking existing code.
6
- *
7
- * OLD LOCATION: lib/evolution-signal.js
8
- * NEW LOCATION: src/core/evolution/* + src/data/repositories/*
9
- *
10
- * @deprecated Use new architecture: import from 'src/core/evolution'
11
- */
12
-
13
- // Import new architecture components
14
- import { EvolutionSignal } from '../src/core/evolution/evolution-signal.js';
15
- import { ThresholdChecker } from '../src/core/evolution/threshold-checker.js';
16
- import { ReviewGate } from '../src/core/evolution/review-gate.js';
17
- import { SignalRepository } from '../src/data/repositories/signal-repository.js';
18
- import { JsonStorage } from '../src/data/storage/json-storage.js';
19
- import { SignalDetector as SignalService } from '../src/core/evolution/signal-detector.js';
20
- import { KNOWLEDGE_DIR } from './config.js';
21
-
22
- // ============================================================================
23
- // BACKWARD COMPATIBLE EXPORTS
24
- // ============================================================================
25
-
26
- // Re-export EvolutionSignal class
27
- export { EvolutionSignal };
28
-
29
- // Lazy-initialized singleton instances
30
- let _storage = null;
31
- let _repository = null;
32
- let _detector = null;
33
-
34
- function getDetector() {
35
- if (!_detector) {
36
- _storage = new JsonStorage(KNOWLEDGE_DIR);
37
- _repository = new SignalRepository(_storage);
38
- _detector = new SignalService(_repository);
39
- }
40
- return _detector;
41
- }
42
-
43
- // ============================================================================
44
- // THRESHOLD CHECKER (Backward Compatible)
45
- // ============================================================================
46
-
47
- /**
48
- * @deprecated Use ThresholdChecker.check() from src/core/evolution
49
- */
50
- export function checkEvolutionThreshold(lesson, threshold = 10) {
51
- return ThresholdChecker.check(lesson, threshold);
52
- }
53
-
54
- /**
55
- * @deprecated Use ThresholdChecker.calculateStability() from src/core/evolution
56
- */
57
- export function calculatePatternStability(violationHistory = []) {
58
- return ThresholdChecker.calculateStability(violationHistory);
59
- }
60
-
61
- // ============================================================================
62
- // SIGNAL QUEUE (Backward Compatible)
63
- // ============================================================================
64
-
65
- /**
66
- * SignalQueue - Backward compatible class
67
- * @deprecated Use SignalRepository + SignalDetector from new architecture
68
- */
69
- class SignalQueueCompat {
70
- get signals() {
71
- // Return cached signals (sync access)
72
- if (!this._cachedSignals) {
73
- // Synchronous fallback - load on first access
74
- this._cachedSignals = [];
75
- this.load().then(signals => {
76
- this._cachedSignals = signals;
77
- });
78
- }
79
- return this._cachedSignals;
80
- }
81
-
82
- async load() {
83
- const detector = getDetector();
84
- const all = await detector.signalRepository.findAll();
85
- this._cachedSignals = all;
86
- return all;
87
- }
88
-
89
- async save() {
90
- // Auto-save through repository (no-op for compatibility)
91
- return;
92
- }
93
-
94
- async add(signal) {
95
- const detector = getDetector();
96
- const result = await detector.queue(
97
- signal.lessonId,
98
- { ready: true, reason: signal.reason, confidence: signal.confidence },
99
- signal.metadata
100
- );
101
- await this.load(); // Refresh cache
102
- return result;
103
- }
104
-
105
- getPending() {
106
- return this.signals.filter(s => s.status === 'pending');
107
- }
108
-
109
- getByLesson(lessonId) {
110
- return this.signals.filter(s => s.lessonId === lessonId);
111
- }
112
-
113
- async approve(signalId) {
114
- const detector = getDetector();
115
- const result = await detector.approve(signalId);
116
- await this.load(); // Refresh cache
117
- return result;
118
- }
119
-
120
- async reject(signalId) {
121
- const detector = getDetector();
122
- const result = await detector.reject(signalId);
123
- await this.load(); // Refresh cache
124
- return result;
125
- }
126
-
127
- async execute(signalId) {
128
- const detector = getDetector();
129
- const result = await detector.execute(signalId);
130
- await this.load(); // Refresh cache
131
- return result;
132
- }
133
-
134
- async cleanup() {
135
- const detector = getDetector();
136
- await detector.signalRepository.cleanup();
137
- await this.load(); // Refresh cache
138
- }
139
- }
140
-
141
- // Singleton instance for backward compatibility
142
- const signalQueueInstance = new SignalQueueCompat();
143
-
144
- // Initialize on module load
145
- signalQueueInstance.load().catch(err => {
146
- console.error('Failed to initialize signal queue:', err);
147
- });
148
-
149
- export { signalQueueInstance as signalQueue };
150
-
151
- // ============================================================================
152
- // REVIEW GATE (Backward Compatible)
153
- // ============================================================================
154
-
155
- /**
156
- * @deprecated Use ReviewGate.evaluate() from src/core/evolution
157
- */
158
- export function reviewGate(signal, settings = {}) {
159
- return ReviewGate.evaluate(signal, settings);
160
- }
161
-
162
- // ============================================================================
163
- // HELPER FUNCTIONS (Backward Compatible)
164
- // ============================================================================
165
-
166
- /**
167
- * @deprecated Use SignalDetector.queue() from new architecture
168
- */
169
- export async function queueEvolutionSignal(lessonId, checkResult, metadata = {}) {
170
- if (!checkResult.ready) return null;
171
-
172
- const signal = new EvolutionSignal(
173
- lessonId,
174
- checkResult.reason,
175
- checkResult.confidence,
176
- metadata
177
- );
178
-
179
- return signalQueueInstance.add(signal);
180
- }
181
-
182
- /**
183
- * @deprecated Use SignalDetector.getStats() from new architecture
184
- */
185
- export async function getEvolutionStats() {
186
- const detector = getDetector();
187
- return detector.getStats();
188
- }
189
-
190
- // ============================================================================
191
- // MIGRATION GUIDE
192
- // ============================================================================
193
-
194
- /**
195
- * HOW TO MIGRATE TO NEW ARCHITECTURE:
196
- *
197
- * OLD CODE:
198
- * ```
199
- * import { signalQueue, checkEvolutionThreshold } from './evolution-signal.js';
200
- *
201
- * const check = checkEvolutionThreshold(lesson, 10);
202
- * await signalQueue.add(signal);
203
- * ```
204
- *
205
- * NEW CODE:
206
- * ```
207
- * import { ThresholdChecker } from '../src/core/evolution/threshold-checker.js';
208
- * import { SignalRepository } from '../src/data/repositories/signal-repository.js';
209
- * import { SignalDetector } from '../src/core/evolution/signal-detector.js';
210
- *
211
- * const check = ThresholdChecker.check(lesson, 10);
212
- * const detector = new SignalDetector(repository);
213
- * await detector.queue(lessonId, check, metadata);
214
- * ```
215
- */
@@ -1,86 +0,0 @@
1
- /**
2
- * @fileoverview Export and Import for PikaKit
3
- * Share settings between projects
4
- */
5
-
6
- import fs from "fs";
7
- import path from "path";
8
- import yaml from "js-yaml";
9
- import { LESSONS_PATH } from "./config.js";
10
- import { SETTINGS_PATH, loadSettings } from "./settings.js";
11
- import { loadKnowledge, saveKnowledge } from "./recall.js";
12
-
13
- /**
14
- * Export lessons and settings to JSON file
15
- * @param {string} outputPath - Output file path
16
- * @returns {boolean}
17
- */
18
- export function exportData(outputPath) {
19
- try {
20
- const data = {
21
- version: 1,
22
- exportedAt: new Date().toISOString(),
23
- lessons: loadKnowledge().lessons || [],
24
- settings: loadSettings()
25
- };
26
-
27
- fs.writeFileSync(outputPath, JSON.stringify(data, null, 2), "utf8");
28
- return true;
29
- } catch (e) {
30
- console.error("Failed to export:", e.message);
31
- return false;
32
- }
33
- }
34
-
35
- /**
36
- * Import data from JSON file
37
- * @param {string} inputPath - Input file path
38
- * @param {"merge" | "replace"} mode - Import mode
39
- * @returns {{ success: boolean, lessonsCount: number, hasSettings: boolean }}
40
- */
41
- export function importData(inputPath, mode = "merge") {
42
- try {
43
- if (!fs.existsSync(inputPath)) {
44
- return { success: false, lessonsCount: 0, hasSettings: false };
45
- }
46
-
47
- const content = fs.readFileSync(inputPath, "utf8");
48
- const data = JSON.parse(content);
49
-
50
- // Import lessons
51
- const currentDb = loadKnowledge();
52
-
53
- if (mode === "replace") {
54
- currentDb.lessons = data.lessons || [];
55
- } else {
56
- // Merge - add new lessons, skip duplicates by pattern
57
- const existingPatterns = new Set(currentDb.lessons.map(l => l.pattern));
58
- for (const lesson of (data.lessons || [])) {
59
- if (!existingPatterns.has(lesson.pattern)) {
60
- currentDb.lessons.push(lesson);
61
- }
62
- }
63
- }
64
-
65
- saveKnowledge(currentDb);
66
-
67
- // Import settings if present
68
- let hasSettings = false;
69
- if (data.settings) {
70
- const settingsPath = SETTINGS_PATH;
71
- fs.writeFileSync(settingsPath, yaml.dump(data.settings), "utf8");
72
- hasSettings = true;
73
- }
74
-
75
- return {
76
- success: true,
77
- lessonsCount: data.lessons?.length || 0,
78
- hasSettings
79
- };
80
- } catch (e) {
81
- console.error("Failed to import:", e.message);
82
- return { success: false, lessonsCount: 0, hasSettings: false };
83
- }
84
- }
85
-
86
- export default { exportData, importData };
@@ -1,65 +0,0 @@
1
- /**
2
- * @fileoverview Tests for export module
3
- */
4
-
5
- import { describe, it, expect, beforeEach, afterEach } from "vitest";
6
- import fs from "fs";
7
- import path from "path";
8
- import os from "os";
9
-
10
- describe("export", () => {
11
- const testDir = path.join(os.tmpdir(), "test-export-" + Date.now());
12
-
13
- beforeEach(() => {
14
- fs.mkdirSync(testDir, { recursive: true });
15
- });
16
-
17
- afterEach(() => {
18
- if (fs.existsSync(testDir)) {
19
- fs.rmSync(testDir, { recursive: true, force: true });
20
- }
21
- });
22
-
23
- describe("export format", () => {
24
- it("creates valid JSON structure", () => {
25
- const data = {
26
- version: 1,
27
- exportedAt: new Date().toISOString(),
28
- lessons: [{ id: "TEST", pattern: "x" }]
29
- };
30
-
31
- const outputPath = path.join(testDir, "export.json");
32
- fs.writeFileSync(outputPath, JSON.stringify(data, null, 2));
33
-
34
- const loaded = JSON.parse(fs.readFileSync(outputPath, "utf8"));
35
- expect(loaded.version).toBe(1);
36
- expect(loaded.lessons).toHaveLength(1);
37
- });
38
-
39
- it("supports lesson array format", () => {
40
- const lessons = [
41
- { id: "L1", pattern: "a", message: "msg" },
42
- { id: "L2", pattern: "b", message: "msg2" }
43
- ];
44
-
45
- const data = { version: 1, lessons };
46
- const json = JSON.stringify(data);
47
- const parsed = JSON.parse(json);
48
-
49
- expect(parsed.lessons).toHaveLength(2);
50
- expect(parsed.lessons[0].id).toBe("L1");
51
- });
52
- });
53
-
54
- describe("import validation", () => {
55
- it("validates version field", () => {
56
- const valid = { version: 1, lessons: [] };
57
- expect(valid.version).toBe(1);
58
- });
59
-
60
- it("validates lessons array", () => {
61
- const valid = { version: 1, lessons: [{ id: "X", pattern: "y" }] };
62
- expect(Array.isArray(valid.lessons)).toBe(true);
63
- });
64
- });
65
- });
@@ -1,337 +0,0 @@
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 };