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.
- package/bin/lib/commands/install.js +67 -45
- package/lib/agent-cli/README.md +21 -0
- package/lib/agent-cli/bin/ag-smart.js +158 -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/auto_preview.py +148 -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/checklist.py +222 -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/session_manager.py +120 -0
- package/lib/agent-cli/lib/settings.js +203 -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 +123 -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 +169 -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/verify_all.py +327 -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/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 +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
|
+
});
|