add-skill-kit 3.2.2 → 3.2.4

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 (72) hide show
  1. package/bin/lib/commands/install.js +67 -45
  2. package/lib/agent-cli/README.md +21 -0
  3. package/lib/agent-cli/bin/ag-smart.js +158 -0
  4. package/lib/agent-cli/lib/audit.js +154 -0
  5. package/lib/agent-cli/lib/audit.test.js +100 -0
  6. package/lib/agent-cli/lib/auto-learn.js +319 -0
  7. package/lib/agent-cli/lib/auto_preview.py +148 -0
  8. package/lib/agent-cli/lib/backup.js +138 -0
  9. package/lib/agent-cli/lib/backup.test.js +78 -0
  10. package/lib/agent-cli/lib/checklist.py +222 -0
  11. package/lib/agent-cli/lib/cognitive-lesson.js +476 -0
  12. package/lib/agent-cli/lib/completion.js +149 -0
  13. package/lib/agent-cli/lib/config.js +35 -0
  14. package/lib/agent-cli/lib/eslint-fix.js +238 -0
  15. package/lib/agent-cli/lib/evolution-signal.js +215 -0
  16. package/lib/agent-cli/lib/export.js +86 -0
  17. package/lib/agent-cli/lib/export.test.js +65 -0
  18. package/lib/agent-cli/lib/fix.js +337 -0
  19. package/lib/agent-cli/lib/fix.test.js +80 -0
  20. package/lib/agent-cli/lib/gemini-export.js +83 -0
  21. package/lib/agent-cli/lib/generate-registry.js +42 -0
  22. package/lib/agent-cli/lib/hooks/install-hooks.js +152 -0
  23. package/lib/agent-cli/lib/hooks/lint-learn.js +172 -0
  24. package/lib/agent-cli/lib/ignore.js +116 -0
  25. package/lib/agent-cli/lib/ignore.test.js +58 -0
  26. package/lib/agent-cli/lib/init.js +124 -0
  27. package/lib/agent-cli/lib/learn.js +255 -0
  28. package/lib/agent-cli/lib/learn.test.js +70 -0
  29. package/lib/agent-cli/lib/migrate-to-v4.js +322 -0
  30. package/lib/agent-cli/lib/proposals.js +199 -0
  31. package/lib/agent-cli/lib/proposals.test.js +56 -0
  32. package/lib/agent-cli/lib/recall.js +820 -0
  33. package/lib/agent-cli/lib/recall.test.js +107 -0
  34. package/lib/agent-cli/lib/selfevolution-bridge.js +167 -0
  35. package/lib/agent-cli/lib/session_manager.py +120 -0
  36. package/lib/agent-cli/lib/settings.js +203 -0
  37. package/lib/agent-cli/lib/skill-learn.js +296 -0
  38. package/lib/agent-cli/lib/stats.js +132 -0
  39. package/lib/agent-cli/lib/stats.test.js +94 -0
  40. package/lib/agent-cli/lib/types.js +33 -0
  41. package/lib/agent-cli/lib/ui/audit-ui.js +146 -0
  42. package/lib/agent-cli/lib/ui/backup-ui.js +107 -0
  43. package/lib/agent-cli/lib/ui/clack-helpers.js +317 -0
  44. package/lib/agent-cli/lib/ui/common.js +83 -0
  45. package/lib/agent-cli/lib/ui/completion-ui.js +126 -0
  46. package/lib/agent-cli/lib/ui/custom-select.js +69 -0
  47. package/lib/agent-cli/lib/ui/dashboard-ui.js +123 -0
  48. package/lib/agent-cli/lib/ui/evolution-signals-ui.js +107 -0
  49. package/lib/agent-cli/lib/ui/export-ui.js +94 -0
  50. package/lib/agent-cli/lib/ui/fix-all-ui.js +191 -0
  51. package/lib/agent-cli/lib/ui/help-ui.js +49 -0
  52. package/lib/agent-cli/lib/ui/index.js +169 -0
  53. package/lib/agent-cli/lib/ui/init-ui.js +56 -0
  54. package/lib/agent-cli/lib/ui/knowledge-ui.js +55 -0
  55. package/lib/agent-cli/lib/ui/learn-ui.js +706 -0
  56. package/lib/agent-cli/lib/ui/lessons-ui.js +148 -0
  57. package/lib/agent-cli/lib/ui/pretty.js +145 -0
  58. package/lib/agent-cli/lib/ui/proposals-ui.js +99 -0
  59. package/lib/agent-cli/lib/ui/recall-ui.js +342 -0
  60. package/lib/agent-cli/lib/ui/routing-demo.js +79 -0
  61. package/lib/agent-cli/lib/ui/routing-ui.js +325 -0
  62. package/lib/agent-cli/lib/ui/settings-ui.js +381 -0
  63. package/lib/agent-cli/lib/ui/stats-ui.js +123 -0
  64. package/lib/agent-cli/lib/ui/watch-ui.js +236 -0
  65. package/lib/agent-cli/lib/verify_all.py +327 -0
  66. package/lib/agent-cli/lib/watcher.js +181 -0
  67. package/lib/agent-cli/lib/watcher.test.js +85 -0
  68. package/lib/agent-cli/package.json +51 -0
  69. package/lib/agentskillskit-cli/README.md +21 -0
  70. package/lib/agentskillskit-cli/ag-smart.js +158 -0
  71. package/lib/agentskillskit-cli/package.json +51 -0
  72. package/package.json +11 -6
@@ -0,0 +1,199 @@
1
+ /**
2
+ * @fileoverview Proposal Generator for Auto-Updating Flow
3
+ * Generates markdown instructions for AI agents to update skills
4
+ */
5
+
6
+ import fs from "fs";
7
+ import path from "path";
8
+ import yaml from "js-yaml";
9
+ import { KNOWLEDGE_DIR, LESSONS_PATH, AGENT_DIR } from "./config.js";
10
+ import { loadSettings } from "./settings.js";
11
+ import { loadKnowledge } from "./recall.js";
12
+
13
+ /** Proposals directory */
14
+ const PROPOSALS_DIR = path.join(KNOWLEDGE_DIR, "proposals");
15
+
16
+ /** Dismissed proposals file */
17
+ const DISMISSED_FILE = path.join(PROPOSALS_DIR, "dismissed.yaml");
18
+
19
+ /**
20
+ * Get lessons that qualify for proposals (hitCount >= threshold)
21
+ * @returns {Array<{ lesson: object, proposalPath: string }>}
22
+ */
23
+ export function getQualifyingLessons() {
24
+ const settings = loadSettings();
25
+ const threshold = settings.updateThreshold || 5;
26
+ const db = loadKnowledge();
27
+
28
+ if (!db.lessons) return [];
29
+
30
+ const dismissed = loadDismissed();
31
+
32
+ return db.lessons
33
+ .filter(l => (l.hitCount || 0) >= threshold && !dismissed.has(l.id))
34
+ .map(lesson => ({
35
+ lesson,
36
+ proposalPath: path.join(PROPOSALS_DIR, `${lesson.id}.md`)
37
+ }));
38
+ }
39
+
40
+ /**
41
+ * Load dismissed proposal IDs
42
+ * @returns {Set<string>}
43
+ */
44
+ function loadDismissed() {
45
+ try {
46
+ if (fs.existsSync(DISMISSED_FILE)) {
47
+ const data = yaml.load(fs.readFileSync(DISMISSED_FILE, "utf8")) || {};
48
+ return new Set(data.dismissed || []);
49
+ }
50
+ } catch (e) { }
51
+ return new Set();
52
+ }
53
+
54
+ /**
55
+ * Dismiss a proposal
56
+ * @param {string} lessonId
57
+ */
58
+ export function dismissProposal(lessonId) {
59
+ fs.mkdirSync(PROPOSALS_DIR, { recursive: true });
60
+ const dismissed = loadDismissed();
61
+ dismissed.add(lessonId);
62
+ fs.writeFileSync(DISMISSED_FILE, yaml.dump({ dismissed: [...dismissed] }), "utf8");
63
+ }
64
+
65
+ /**
66
+ * Generate proposal markdown for AI agent
67
+ * @param {object} lesson - Lesson object
68
+ * @returns {string} Markdown content
69
+ */
70
+ export function generateProposalMarkdown(lesson) {
71
+ const skillHint = guessSkillFromLesson(lesson);
72
+
73
+ return `# 🤖 Skill Update Proposal
74
+
75
+ ## Pattern Detected
76
+ | Field | Value |
77
+ |-------|-------|
78
+ | **ID** | \`${lesson.id}\` |
79
+ | **Hit Count** | ${lesson.hitCount || 0} |
80
+ | **Severity** | ${lesson.severity || "WARNING"} |
81
+ | **Last Hit** | ${lesson.lastHit || "N/A"} |
82
+
83
+ ## Message
84
+ > ${lesson.message}
85
+
86
+ ## Pattern (Regex)
87
+ \`\`\`
88
+ ${lesson.pattern}
89
+ \`\`\`
90
+
91
+ ---
92
+
93
+ ## 📝 Suggested Action for AI Agent
94
+
95
+ Please update the relevant skill file to include this rule:
96
+
97
+ ### Target File
98
+ \`${skillHint}\`
99
+
100
+ ### Add to Rules Section
101
+ \`\`\`markdown
102
+ ### ${lesson.message}
103
+ - Pattern: \`${lesson.pattern}\`
104
+ - Severity: ${lesson.severity || "WARNING"}
105
+ - Auto-learned from violations
106
+ \`\`\`
107
+
108
+ ---
109
+
110
+ ## How to Apply
111
+
112
+ 1. **Copy this entire proposal**
113
+ 2. **Paste to your AI coding agent** (Claude, Gemini, etc.)
114
+ 3. **Ask:** "Update the skill file with this rule"
115
+
116
+ The AI agent will modify the appropriate \`.agent/skills/*/SKILL.md\` file.
117
+
118
+ ---
119
+
120
+ *Generated by Agent Skill Kit v2.1.0*
121
+ `;
122
+ }
123
+
124
+ /**
125
+ * Guess which skill file this lesson relates to
126
+ * @param {object} lesson
127
+ * @returns {string}
128
+ */
129
+ function guessSkillFromLesson(lesson) {
130
+ const pattern = (lesson.pattern || "").toLowerCase();
131
+ const message = (lesson.message || "").toLowerCase();
132
+ const combined = pattern + " " + message;
133
+
134
+ // Frontend patterns
135
+ if (combined.includes("react") || combined.includes("component") || combined.includes("hook") || combined.includes("usestate") || combined.includes("useeffect")) {
136
+ return ".agent/skills/react-patterns/SKILL.md";
137
+ }
138
+ if (combined.includes("next") || combined.includes("getserverside") || combined.includes("getstaticprops") || combined.includes("app router")) {
139
+ return ".agent/skills/nextjs-best-practices/SKILL.md";
140
+ }
141
+ if (combined.includes("css") || combined.includes("style") || combined.includes("tailwind") || combined.includes("classname")) {
142
+ return ".agent/skills/frontend-design/SKILL.md";
143
+ }
144
+
145
+ // Backend patterns
146
+ if (combined.includes("api") || combined.includes("fetch") || combined.includes("http") || combined.includes("endpoint") || combined.includes("rest")) {
147
+ return ".agent/skills/api-patterns/SKILL.md";
148
+ }
149
+ if (combined.includes("database") || combined.includes("sql") || combined.includes("prisma") || combined.includes("query") || combined.includes("schema")) {
150
+ return ".agent/skills/database-design/SKILL.md";
151
+ }
152
+ if (combined.includes("node") || combined.includes("express") || combined.includes("server") || combined.includes("middleware")) {
153
+ return ".agent/skills/nodejs-best-practices/SKILL.md";
154
+ }
155
+
156
+ // Testing patterns
157
+ if (combined.includes("test") || combined.includes("mock") || combined.includes("jest") || combined.includes("vitest") || combined.includes("expect")) {
158
+ return ".agent/skills/testing-patterns/SKILL.md";
159
+ }
160
+
161
+ // TypeScript patterns
162
+ if (combined.includes("typescript") || combined.includes("type") || combined.includes("interface") || combined.includes("generic") || combined.includes("any")) {
163
+ return ".agent/skills/typescript-expert/SKILL.md";
164
+ }
165
+
166
+ // Security patterns
167
+ if (combined.includes("security") || combined.includes("auth") || combined.includes("password") || combined.includes("token") || combined.includes("xss") || combined.includes("injection")) {
168
+ return ".agent/skills/vulnerability-scanner/SKILL.md";
169
+ }
170
+
171
+ // Performance patterns
172
+ if (combined.includes("performance") || combined.includes("memo") || combined.includes("lazy") || combined.includes("cache") || combined.includes("optimize")) {
173
+ return ".agent/skills/performance-profiling/SKILL.md";
174
+ }
175
+
176
+ // Git patterns
177
+ if (combined.includes("commit") || combined.includes("branch") || combined.includes("merge") || combined.includes("git")) {
178
+ return ".agent/skills/git-conventions/SKILL.md";
179
+ }
180
+
181
+ // Default to clean-code for general patterns
182
+ return ".agent/skills/clean-code/SKILL.md";
183
+ }
184
+
185
+ /**
186
+ * Count pending proposals
187
+ * @returns {number}
188
+ */
189
+ export function countPendingProposals() {
190
+ return getQualifyingLessons().length;
191
+ }
192
+
193
+ export default {
194
+ getQualifyingLessons,
195
+ dismissProposal,
196
+ generateProposalMarkdown,
197
+ countPendingProposals,
198
+ PROPOSALS_DIR
199
+ };
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @fileoverview Tests for proposals module
3
+ */
4
+
5
+ import { describe, it, expect } from "vitest";
6
+
7
+ // Test proposal markdown generation without mocking
8
+ describe("proposals", () => {
9
+ describe("generateProposalMarkdown format", () => {
10
+ it("creates markdown with required sections", () => {
11
+ const lesson = {
12
+ id: "LEARN-001",
13
+ pattern: "console\\.log",
14
+ message: "No console.log in production",
15
+ hitCount: 5,
16
+ severity: "ERROR"
17
+ };
18
+
19
+ // Simulate markdown generation
20
+ const md = `# 🤖 Skill Update Proposal\n\n## Pattern Detected\n| Field | Value |\n|-------|-------|\n| **ID** | \`${lesson.id}\` |\n| **Hit Count** | ${lesson.hitCount || 0} |\n\n## Message\n> ${lesson.message}`;
21
+
22
+ expect(md).toContain("LEARN-001");
23
+ expect(md).toContain("No console.log");
24
+ expect(md).toContain("5");
25
+ });
26
+
27
+ it("includes AI agent instructions", () => {
28
+ const md = `## How to Apply\n1. **Copy this entire proposal**\n2. **Paste to your AI coding agent**`;
29
+
30
+ expect(md).toContain("Copy");
31
+ expect(md).toContain("Paste");
32
+ expect(md).toContain("AI");
33
+ });
34
+ });
35
+
36
+ describe("proposal threshold", () => {
37
+ it("default threshold is 5", () => {
38
+ const defaultThreshold = 5;
39
+ expect(defaultThreshold).toBe(5);
40
+ });
41
+
42
+ it("lesson qualifies when hitCount >= threshold", () => {
43
+ const threshold = 5;
44
+ const lessons = [
45
+ { id: "L1", hitCount: 5 },
46
+ { id: "L2", hitCount: 3 },
47
+ { id: "L3", hitCount: 10 }
48
+ ];
49
+
50
+ const qualifying = lessons.filter(l => l.hitCount >= threshold);
51
+ expect(qualifying).toHaveLength(2);
52
+ expect(qualifying.map(l => l.id)).toContain("L1");
53
+ expect(qualifying.map(l => l.id)).toContain("L3");
54
+ });
55
+ });
56
+ });