claudify-agent 0.0.0-stage → 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 (48) hide show
  1. package/.claude/QUICK-REFERENCE.md +213 -0
  2. package/.claude/cost-dashboard.md +162 -0
  3. package/.claude/docs/COST-OPTIMIZATION.md +403 -0
  4. package/.claude/docs/MCP-INTEGRATION-GUIDE.md +348 -0
  5. package/.claude/docs/PLAN-MODE-OPTIMIZATION.md +836 -0
  6. package/.claude/hooks/auto-learning-review.ts +195 -0
  7. package/.claude/hooks/auto-lint-fix.ts +104 -0
  8. package/.claude/hooks/auto-security-review.ts +354 -0
  9. package/.claude/hooks/auto-validate.ts +348 -0
  10. package/.claude/hooks/plan-quality-tracker.ts +719 -0
  11. package/.claude/rules/anti-patterns.md +22 -0
  12. package/.claude/rules/context-tier-1.md +41 -0
  13. package/.claude/rules/context-tier-2.md +285 -0
  14. package/.claude/rules/general.md +25 -0
  15. package/.claude/rules/mcp-auto-use.md +46 -0
  16. package/.claude/rules/parallel-exploration-auto.md +31 -0
  17. package/.claude/rules/plan-mode-execution.md +289 -0
  18. package/.claude/rules/plan-mode-research.md +34 -0
  19. package/.claude/rules/plan-mode-structure.md +166 -0
  20. package/.claude/rules/plan-mode-validation.md +130 -0
  21. package/.claude/rules/security-critical.md +19 -0
  22. package/.claude/rules/tool-auto-selection.md +45 -0
  23. package/.claude/rules/tool-strategy.md +22 -0
  24. package/.claude/scripts/auto-validate.js +69 -0
  25. package/.claude/scripts/security-scan.js +45 -0
  26. package/.claude/security-dashboard.md +142 -0
  27. package/.claude/skills/backend-concurrency/SKILL.md +203 -0
  28. package/.claude/skills/debug-optimizer/SKILL.md +399 -0
  29. package/.claude/skills/debug-optimizer.md +12 -0
  30. package/.claude/skills/golang-guide/SKILL.md +177 -0
  31. package/.claude/skills/learning-loop/SKILL.md +308 -0
  32. package/.claude/skills/mcp-mastery/SKILL.md +214 -0
  33. package/.claude/skills/nestjs-guide/SKILL.md +197 -0
  34. package/.claude/skills/nextjs-guide/SKILL.md +687 -0
  35. package/.claude/skills/nextjs.md +13 -0
  36. package/.claude/skills/parallel-exploration/SKILL.md +193 -0
  37. package/.claude/skills/plan-mode-mastery/SKILL.md +263 -0
  38. package/.claude/skills/python-guide/SKILL.md +822 -0
  39. package/.claude/skills/react-guide/SKILL.md +762 -0
  40. package/.claude/skills/react.md +12 -0
  41. package/.claude/skills/security.md +18 -0
  42. package/.claude/skills/solidity-guide/SKILL.md +32 -0
  43. package/.claude/skills/tool-selection/SKILL.md +428 -0
  44. package/.claude/skills/vite-guide/SKILL.md +445 -0
  45. package/CLAUDE.md +49 -0
  46. package/README.md +65 -2
  47. package/bin/cli.js +50 -0
  48. package/package.json +44 -4
@@ -0,0 +1,348 @@
1
+ // .cursor/hooks/auto-validate.ts
2
+ // Unified validation hook: lint + typecheck + tests + MCP validation
3
+
4
+ import { execSync } from "child_process";
5
+ import { readFileSync, writeFileSync, existsSync } from "fs";
6
+ import { join } from "path";
7
+
8
+ export {};
9
+
10
+ interface StopHookInput {
11
+ conversation_id: string;
12
+ status: "completed" | "aborted" | "error";
13
+ loop_count: number;
14
+ }
15
+
16
+ interface StopHookOutput {
17
+ followup_message?: string;
18
+ }
19
+
20
+ interface ValidationResult {
21
+ name: string;
22
+ passed: boolean;
23
+ error?: string;
24
+ skipped?: boolean;
25
+ }
26
+
27
+ interface MCPToolResult {
28
+ tool: string;
29
+ success: boolean;
30
+ error?: string;
31
+ }
32
+
33
+ interface ValidationConfig {
34
+ enableLint?: boolean;
35
+ enableTypecheck?: boolean;
36
+ enableTests?: boolean;
37
+ enableMCPValidation?: boolean;
38
+ testCommand?: string;
39
+ lintCommand?: string;
40
+ typecheckCommand?: string;
41
+ }
42
+
43
+ interface HooksConfig {
44
+ validation?: ValidationConfig;
45
+ reporting?: {
46
+ generateReports?: boolean;
47
+ reportDirectory?: string;
48
+ appendReports?: boolean;
49
+ };
50
+ }
51
+
52
+ // Read input from stdin
53
+ const stdin = await new Promise<string>((resolve) => {
54
+ let data = "";
55
+ process.stdin.on("data", (chunk) => (data += chunk));
56
+ process.stdin.on("end", () => resolve(data));
57
+ });
58
+
59
+ const input: StopHookInput = JSON.parse(stdin);
60
+
61
+ // Load optional configuration
62
+ const configPath = join(process.cwd(), '.cursor/hooks.config.json');
63
+ const config: HooksConfig = existsSync(configPath)
64
+ ? JSON.parse(readFileSync(configPath, 'utf-8'))
65
+ : {};
66
+
67
+ const validationConfig = {
68
+ enableLint: config.validation?.enableLint !== false,
69
+ enableTypecheck: config.validation?.enableTypecheck !== false,
70
+ enableTests: config.validation?.enableTests !== false,
71
+ enableMCPValidation: config.validation?.enableMCPValidation !== false,
72
+ lintCommand: config.validation?.lintCommand,
73
+ typecheckCommand: config.validation?.typecheckCommand,
74
+ testCommand: config.validation?.testCommand
75
+ };
76
+
77
+ const reportingConfig = {
78
+ generateReports: config.reporting?.generateReports !== false,
79
+ reportDirectory: config.reporting?.reportDirectory || '.cursor',
80
+ appendReports: config.reporting?.appendReports !== false
81
+ };
82
+
83
+ // Only validate on completion
84
+ if (input.status !== "completed") {
85
+ console.log(JSON.stringify({}));
86
+ process.exit(0);
87
+ }
88
+
89
+ // Helper functions
90
+ function hasScript(scriptName: string): boolean {
91
+ try {
92
+ const pkgPath = join(process.cwd(), 'package.json');
93
+ if (!existsSync(pkgPath)) return false;
94
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
95
+ return !!pkg.scripts?.[scriptName];
96
+ } catch {
97
+ return false;
98
+ }
99
+ }
100
+
101
+ function detectCodeChanges(conversation: any): boolean {
102
+ if (!conversation?.messages) return false;
103
+
104
+ return conversation.messages.some((m: any) =>
105
+ m.content?.includes('StrReplace') ||
106
+ m.content?.includes('Write') ||
107
+ m.content?.includes('EditNotebook') ||
108
+ m.tool_calls?.some((t: any) =>
109
+ ['StrReplace', 'Write', 'EditNotebook'].includes(t.function?.name)
110
+ )
111
+ );
112
+ }
113
+
114
+ function validateMCPTools(conversation: any): MCPToolResult[] {
115
+ const results: MCPToolResult[] = [];
116
+
117
+ if (!conversation?.messages) return results;
118
+
119
+ const mcpToolPatterns = [
120
+ 'browser_', 'github_', 'eslint', 'context7',
121
+ 'chrome', 'playwright', 'selenium', 'dart', 'stitch', 'shadcn'
122
+ ];
123
+
124
+ for (const message of conversation.messages) {
125
+ if (message.tool_calls) {
126
+ for (const toolCall of message.tool_calls) {
127
+ const toolName = toolCall.function?.name;
128
+ if (!toolName) continue;
129
+
130
+ const isMCPTool = mcpToolPatterns.some(pattern =>
131
+ toolName.startsWith(pattern) || toolName.includes(pattern)
132
+ );
133
+
134
+ if (isMCPTool) {
135
+ // Track MCP tool usage (simplified - assumes success)
136
+ // In production, would check actual tool execution results
137
+ results.push({
138
+ tool: toolName,
139
+ success: true
140
+ });
141
+ }
142
+ }
143
+ }
144
+ }
145
+
146
+ return results;
147
+ }
148
+
149
+ function detectTestFiles(conversation: any): boolean {
150
+ if (!conversation?.messages) return false;
151
+
152
+ return conversation.messages.some((m: any) =>
153
+ m.content?.includes('.test.ts') ||
154
+ m.content?.includes('.test.tsx') ||
155
+ m.content?.includes('.spec.ts') ||
156
+ m.content?.includes('.spec.tsx') ||
157
+ m.content?.includes('__tests__') ||
158
+ m.content?.includes('.test.js') ||
159
+ m.content?.includes('.spec.js')
160
+ );
161
+ }
162
+
163
+ // Try to detect code changes from conversation file
164
+ const conversationFile = join(process.cwd(), `.cursor/conversations/${input.conversation_id}.json`);
165
+ let conversation;
166
+ try {
167
+ if (existsSync(conversationFile)) {
168
+ conversation = JSON.parse(readFileSync(conversationFile, 'utf-8'));
169
+ }
170
+ } catch {
171
+ console.error("[Auto-Validate] Could not read conversation file, proceeding with validation");
172
+ conversation = null;
173
+ }
174
+
175
+ // Smart change detection
176
+ const hasCodeChanges = conversation ? detectCodeChanges(conversation) : true;
177
+
178
+ if (!hasCodeChanges) {
179
+ console.error("[Auto-Validate] No code changes detected, skipping validation");
180
+ console.log(JSON.stringify({}));
181
+ process.exit(0);
182
+ }
183
+
184
+ console.error("[Auto-Validate] Running automatic validation...");
185
+
186
+ // Automatic validation sequence
187
+ const validations: ValidationResult[] = [];
188
+
189
+ // 1. Run ESLint (with graceful degradation)
190
+ if (validationConfig.enableLint) {
191
+ const lintCommand = validationConfig.lintCommand || (hasScript('lint') ? 'npm run lint' : null);
192
+
193
+ if (lintCommand) {
194
+ try {
195
+ execSync(lintCommand, { stdio: 'pipe', encoding: 'utf-8', timeout: 60000 });
196
+ validations.push({ name: 'ESLint', passed: true });
197
+ console.error("[Auto-Validate] ✓ ESLint passed");
198
+ } catch (error: any) {
199
+ validations.push({
200
+ name: 'ESLint',
201
+ passed: false,
202
+ error: error.stdout?.toString() || error.stderr?.toString() || error.message
203
+ });
204
+ console.error("[Auto-Validate] ✗ ESLint failed");
205
+ }
206
+ } else {
207
+ validations.push({ name: 'ESLint', passed: true, skipped: true });
208
+ console.error("[Auto-Validate] ⚠ ESLint skipped (no lint script found)");
209
+ }
210
+ } else {
211
+ validations.push({ name: 'ESLint', passed: true, skipped: true });
212
+ console.error("[Auto-Validate] ⚠ ESLint disabled in config");
213
+ }
214
+
215
+ // 2. Run typecheck (with graceful degradation)
216
+ if (validationConfig.enableTypecheck) {
217
+ const typecheckCommand = validationConfig.typecheckCommand || (hasScript('typecheck') ? 'npm run typecheck' : null);
218
+
219
+ if (typecheckCommand) {
220
+ try {
221
+ execSync(typecheckCommand, { stdio: 'pipe', encoding: 'utf-8', timeout: 60000 });
222
+ validations.push({ name: 'Typecheck', passed: true });
223
+ console.error("[Auto-Validate] ✓ Typecheck passed");
224
+ } catch (error: any) {
225
+ validations.push({
226
+ name: 'Typecheck',
227
+ passed: false,
228
+ error: error.stdout?.toString() || error.stderr?.toString() || error.message
229
+ });
230
+ console.error("[Auto-Validate] ✗ Typecheck failed");
231
+ }
232
+ } else {
233
+ validations.push({ name: 'Typecheck', passed: true, skipped: true });
234
+ console.error("[Auto-Validate] ⚠ Typecheck skipped (no typecheck script found)");
235
+ }
236
+ } else {
237
+ validations.push({ name: 'Typecheck', passed: true, skipped: true });
238
+ console.error("[Auto-Validate] ⚠ Typecheck disabled in config");
239
+ }
240
+
241
+ // 3. Run tests (if test files detected or configured)
242
+ const hasTestFiles = conversation ? detectTestFiles(conversation) : false;
243
+ const shouldRunTests = validationConfig.enableTests && (hasTestFiles || hasScript('test'));
244
+
245
+ if (shouldRunTests) {
246
+ const testCommand = validationConfig.testCommand || 'npm run test';
247
+
248
+ if (hasScript('test') || validationConfig.testCommand) {
249
+ try {
250
+ execSync(testCommand, {
251
+ stdio: 'pipe',
252
+ encoding: 'utf-8',
253
+ timeout: 120000 // 120s timeout for test suites
254
+ });
255
+ validations.push({ name: 'Tests', passed: true });
256
+ console.error("[Auto-Validate] ✓ Tests passed");
257
+ } catch (error: any) {
258
+ validations.push({
259
+ name: 'Tests',
260
+ passed: false,
261
+ error: error.stdout?.toString() || error.stderr?.toString() || error.message
262
+ });
263
+ console.error("[Auto-Validate] ✗ Tests failed");
264
+ }
265
+ } else {
266
+ validations.push({ name: 'Tests', passed: true, skipped: true });
267
+ console.error("[Auto-Validate] ⚠ Tests skipped (no test script found)");
268
+ }
269
+ } else {
270
+ if (!validationConfig.enableTests) {
271
+ validations.push({ name: 'Tests', passed: true, skipped: true });
272
+ console.error("[Auto-Validate] ⚠ Tests disabled in config");
273
+ } else {
274
+ validations.push({ name: 'Tests', passed: true, skipped: true });
275
+ console.error("[Auto-Validate] ⚠ Tests skipped (no test files detected)");
276
+ }
277
+ }
278
+
279
+ // 4. Validate MCP tools (if MCP tools were used)
280
+ if (validationConfig.enableMCPValidation && conversation) {
281
+ const mcpResults = validateMCPTools(conversation);
282
+
283
+ if (mcpResults.length > 0) {
284
+ const failedMCPTools = mcpResults.filter(r => !r.success);
285
+
286
+ if (failedMCPTools.length > 0) {
287
+ validations.push({
288
+ name: 'MCP Tools',
289
+ passed: false,
290
+ error: `Failed tools: ${failedMCPTools.map(t => t.tool).join(', ')}`
291
+ });
292
+ console.error(`[Auto-Validate] ✗ ${failedMCPTools.length} MCP tool(s) failed validation`);
293
+ } else {
294
+ validations.push({ name: 'MCP Tools', passed: true });
295
+ console.error(`[Auto-Validate] ✓ ${mcpResults.length} MCP tool(s) validated successfully`);
296
+ }
297
+ }
298
+ } else if (!validationConfig.enableMCPValidation) {
299
+ console.error("[Auto-Validate] ⚠ MCP validation disabled in config");
300
+ }
301
+
302
+ // Generate validation report (if enabled)
303
+ const failedValidations = validations.filter(v => !v.passed && !v.skipped);
304
+ const passedCount = validations.filter(v => v.passed && !v.skipped).length;
305
+ const skippedCount = validations.filter(v => v.skipped).length;
306
+
307
+ const reportPath = join(process.cwd(), reportingConfig.reportDirectory, 'auto-validation-report.md');
308
+
309
+ if (reportingConfig.generateReports) {
310
+ const validationReport = `## Auto-Validation Report
311
+
312
+ Generated: ${new Date().toISOString()}
313
+ Conversation: ${input.conversation_id}
314
+
315
+ ## Results
316
+
317
+ ${validations.map(v => {
318
+ if (v.skipped) {
319
+ return `⚠️ ${v.name} (skipped)`;
320
+ }
321
+ return `${v.passed ? '✅' : '❌'} ${v.name}${v.error ? `:\n\`\`\`${v.error}\`\`\`` : ''}`;
322
+ }).join('\n\n')}
323
+
324
+ ## Summary
325
+
326
+ Total: ${validations.length} checks
327
+ Passed: ${passedCount}
328
+ Failed: ${failedValidations.length}
329
+ Skipped: ${skippedCount}
330
+ ${failedValidations.length === 0 ? '\n✓ All validations passed!' : '\n⚠️ Some validations failed. Please fix the issues above.'}
331
+ `;
332
+
333
+ writeFileSync(reportPath, validationReport);
334
+ console.error(`[Auto-Validate] Report saved to ${reportPath}`);
335
+ } else {
336
+ console.error("[Auto-Validate] ⚠ Report generation disabled in config");
337
+ }
338
+
339
+ // Provide feedback
340
+ if (failedValidations.length > 0) {
341
+ const output: StopHookOutput = {
342
+ followup_message: `⚠️ Validation failed: ${failedValidations.map(v => v.name).join(', ')}. See ${reportPath} for details.`,
343
+ };
344
+ console.log(JSON.stringify(output));
345
+ } else {
346
+ console.error("[Auto-Validate] ✓ All validations passed");
347
+ console.log(JSON.stringify({}));
348
+ }