@itz4blitz/agentful 0.3.0 → 0.5.1

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 (94) hide show
  1. package/README.md +139 -10
  2. package/bin/cli.js +1032 -48
  3. package/bin/hooks/README.md +338 -82
  4. package/bin/hooks/analyze-trigger.js +69 -0
  5. package/bin/hooks/block-random-docs.js +77 -0
  6. package/bin/hooks/health-check.js +153 -0
  7. package/bin/hooks/post-agent.js +101 -0
  8. package/bin/hooks/post-feature.js +227 -0
  9. package/bin/hooks/pre-agent.js +118 -0
  10. package/bin/hooks/pre-feature.js +138 -0
  11. package/lib/VALIDATION_README.md +455 -0
  12. package/lib/atomic.js +350 -0
  13. package/lib/ci/claude-action-integration.js +641 -0
  14. package/lib/ci/index.js +10 -0
  15. package/lib/core/CLAUDE_EXECUTOR.md +371 -0
  16. package/lib/core/README.md +321 -0
  17. package/lib/core/analyzer.js +497 -0
  18. package/lib/core/claude-executor.example.js +210 -0
  19. package/lib/core/claude-executor.js +1046 -0
  20. package/lib/core/cli.js +141 -0
  21. package/lib/core/detectors/conventions.js +342 -0
  22. package/lib/core/detectors/framework.js +276 -0
  23. package/lib/core/detectors/index.js +15 -0
  24. package/lib/core/detectors/language.js +199 -0
  25. package/lib/core/detectors/patterns.js +356 -0
  26. package/lib/core/generator.js +626 -0
  27. package/lib/core/index.js +9 -0
  28. package/lib/core/output-parser.example.js +250 -0
  29. package/lib/core/output-parser.js +458 -0
  30. package/lib/core/storage.js +515 -0
  31. package/lib/core/templates.js +556 -0
  32. package/lib/index.js +32 -0
  33. package/lib/init.js +497 -25
  34. package/lib/pipeline/cli.js +423 -0
  35. package/lib/pipeline/engine.js +928 -0
  36. package/lib/pipeline/executor.js +440 -0
  37. package/lib/pipeline/index.js +33 -0
  38. package/lib/pipeline/integrations.js +559 -0
  39. package/lib/pipeline/schemas.js +288 -0
  40. package/lib/presets.js +207 -0
  41. package/lib/remote/client.js +361 -0
  42. package/lib/server/auth.js +286 -0
  43. package/lib/server/client-example.js +190 -0
  44. package/lib/server/executor.js +426 -0
  45. package/lib/server/index.js +469 -0
  46. package/lib/update-helpers.js +505 -0
  47. package/lib/validation.js +460 -0
  48. package/package.json +19 -2
  49. package/template/.claude/agents/architect.md +260 -0
  50. package/template/.claude/agents/backend.md +203 -0
  51. package/template/.claude/agents/fixer.md +244 -0
  52. package/template/.claude/agents/frontend.md +232 -0
  53. package/template/.claude/agents/orchestrator.md +528 -0
  54. package/template/.claude/agents/product-analyzer.md +1130 -0
  55. package/template/.claude/agents/reviewer.md +229 -0
  56. package/template/.claude/agents/tester.md +242 -0
  57. package/{.claude → template/.claude}/commands/agentful-analyze.md +151 -43
  58. package/template/.claude/commands/agentful-decide.md +470 -0
  59. package/{.claude → template/.claude}/commands/agentful-product.md +92 -8
  60. package/template/.claude/commands/agentful-start.md +432 -0
  61. package/{.claude → template/.claude}/commands/agentful-status.md +88 -3
  62. package/template/.claude/commands/agentful-update.md +402 -0
  63. package/template/.claude/commands/agentful-validate.md +369 -0
  64. package/{.claude → template/.claude}/commands/agentful.md +111 -195
  65. package/template/.claude/product/EXAMPLES.md +167 -0
  66. package/{.claude → template/.claude}/settings.json +9 -13
  67. package/{.claude → template/.claude}/skills/conversation/SKILL.md +13 -7
  68. package/template/.claude/skills/deployment/SKILL.md +116 -0
  69. package/template/.claude/skills/product-planning/SKILL.md +463 -0
  70. package/{.claude → template/.claude}/skills/product-tracking/SKILL.md +10 -21
  71. package/template/.claude/skills/testing/SKILL.md +228 -0
  72. package/template/.claude/skills/validation/SKILL.md +650 -0
  73. package/template/CLAUDE.md +84 -16
  74. package/template/bin/hooks/block-random-docs.js +121 -0
  75. package/version.json +1 -1
  76. package/.claude/agents/architect.md +0 -524
  77. package/.claude/agents/backend.md +0 -315
  78. package/.claude/agents/fixer.md +0 -263
  79. package/.claude/agents/frontend.md +0 -274
  80. package/.claude/agents/orchestrator.md +0 -283
  81. package/.claude/agents/product-analyzer.md +0 -799
  82. package/.claude/agents/reviewer.md +0 -332
  83. package/.claude/agents/tester.md +0 -410
  84. package/.claude/commands/agentful-decide.md +0 -214
  85. package/.claude/commands/agentful-start.md +0 -182
  86. package/.claude/commands/agentful-validate.md +0 -127
  87. package/.claude/product/EXAMPLES.md +0 -610
  88. package/.claude/product/README.md +0 -344
  89. package/.claude/skills/validation/SKILL.md +0 -271
  90. package/bin/hooks/analyze-trigger.sh +0 -57
  91. package/bin/hooks/health-check.sh +0 -36
  92. package/template/PRODUCT.md +0 -584
  93. /package/{.claude → template/.claude}/commands/agentful-generate.md +0 -0
  94. /package/{.claude → template/.claude}/product/index.md +0 -0
@@ -0,0 +1,356 @@
1
+ import path from 'path';
2
+ import fs from 'fs/promises';
3
+
4
+ /**
5
+ * Pattern Detector
6
+ *
7
+ * Detects code patterns and architectural styles:
8
+ * - Component patterns (React, Vue, etc.)
9
+ * - API patterns (REST, GraphQL, RPC)
10
+ * - Database patterns (SQL, NoSQL, ORM)
11
+ * - Test patterns (unit, integration, e2e)
12
+ * - Authentication patterns (JWT, OAuth, sessions)
13
+ */
14
+
15
+ /**
16
+ * Detect component patterns
17
+ *
18
+ * @param {string[]} files - Array of file paths
19
+ * @param {string} projectRoot - Absolute path to project root
20
+ * @returns {Promise<Object>} Component pattern detection result
21
+ */
22
+ export async function detectComponentPatterns(files, projectRoot) {
23
+ const componentFiles = files.filter(file =>
24
+ /\.(jsx|tsx|vue|svelte)$/.test(file) ||
25
+ file.includes('/components/') ||
26
+ file.includes('/ui/')
27
+ );
28
+
29
+ if (componentFiles.length === 0) {
30
+ return { detected: false };
31
+ }
32
+
33
+ const examples = componentFiles.slice(0, 5);
34
+ const patterns = {
35
+ functional: 0,
36
+ class: 0,
37
+ hooks: 0
38
+ };
39
+
40
+ // Sample a few files to detect patterns
41
+ for (const file of examples.slice(0, 3)) {
42
+ try {
43
+ const filePath = path.join(projectRoot, file);
44
+ const content = await fs.readFile(filePath, 'utf-8');
45
+
46
+ if (/export\s+default\s+function|const\s+\w+\s*=\s*\(\)/.test(content)) {
47
+ patterns.functional++;
48
+ }
49
+ if (/class\s+\w+\s+extends/.test(content)) {
50
+ patterns.class++;
51
+ }
52
+ if (/use[A-Z]\w+/.test(content)) {
53
+ patterns.hooks++;
54
+ }
55
+ } catch (error) {
56
+ // Skip files that can't be read
57
+ }
58
+ }
59
+
60
+ return {
61
+ detected: true,
62
+ count: componentFiles.length,
63
+ examples: examples.map(f => path.basename(f)),
64
+ style: patterns.functional > patterns.class ? 'functional' : 'class',
65
+ usesHooks: patterns.hooks > 0
66
+ };
67
+ }
68
+
69
+ /**
70
+ * Detect API patterns
71
+ *
72
+ * @param {string[]} files - Array of file paths
73
+ * @param {string} projectRoot - Absolute path to project root
74
+ * @returns {Promise<Object>} API pattern detection result
75
+ */
76
+ export async function detectAPIPatterns(files, projectRoot) {
77
+ const apiFiles = files.filter(file =>
78
+ file.includes('/api/') ||
79
+ file.includes('/routes/') ||
80
+ file.includes('/controllers/') ||
81
+ file.includes('/endpoints/')
82
+ );
83
+
84
+ if (apiFiles.length === 0) {
85
+ return { detected: false };
86
+ }
87
+
88
+ const patterns = {
89
+ rest: 0,
90
+ graphql: 0,
91
+ rpc: 0
92
+ };
93
+
94
+ // Check for GraphQL files
95
+ const hasGraphQL = files.some(file =>
96
+ file.endsWith('.graphql') ||
97
+ file.endsWith('.gql') ||
98
+ file.includes('schema.') ||
99
+ file.includes('resolvers')
100
+ );
101
+ if (hasGraphQL) patterns.graphql++;
102
+
103
+ // Check for RPC/tRPC
104
+ const hasRPC = files.some(file =>
105
+ file.includes('trpc') ||
106
+ file.includes('.proto') ||
107
+ file.includes('grpc')
108
+ );
109
+ if (hasRPC) patterns.rpc++;
110
+
111
+ // Default to REST if API files exist
112
+ if (apiFiles.length > 0) patterns.rest++;
113
+
114
+ // Determine pattern directories
115
+ const apiDirs = new Set();
116
+ for (const file of apiFiles) {
117
+ const dir = path.dirname(file);
118
+ const parts = dir.split('/');
119
+ if (parts.includes('api')) {
120
+ apiDirs.add(parts.slice(0, parts.indexOf('api') + 1).join('/'));
121
+ }
122
+ }
123
+
124
+ return {
125
+ detected: true,
126
+ pattern: Array.from(apiDirs)[0] || 'api/',
127
+ count: apiFiles.length,
128
+ type: patterns.graphql > 0 ? 'GraphQL' : patterns.rpc > 0 ? 'RPC' : 'REST',
129
+ examples: apiFiles.slice(0, 3).map(f => path.basename(f))
130
+ };
131
+ }
132
+
133
+ /**
134
+ * Detect database patterns
135
+ *
136
+ * @param {string[]} files - Array of file paths
137
+ * @param {string} projectRoot - Absolute path to project root
138
+ * @returns {Promise<Object>} Database pattern detection result
139
+ */
140
+ export async function detectDatabasePatterns(files, projectRoot) {
141
+ const dbFiles = files.filter(file =>
142
+ file.includes('/models/') ||
143
+ file.includes('/entities/') ||
144
+ file.includes('/schema') ||
145
+ file.includes('/migrations/') ||
146
+ file.includes('prisma/') ||
147
+ file.includes('database/')
148
+ );
149
+
150
+ const patterns = {
151
+ orm: null,
152
+ migrations: false,
153
+ type: 'unknown'
154
+ };
155
+
156
+ // Check for ORM
157
+ if (files.some(file => file.includes('prisma/schema.prisma'))) {
158
+ patterns.orm = 'Prisma';
159
+ patterns.type = 'SQL';
160
+ } else if (files.some(file => file.includes('drizzle.config'))) {
161
+ patterns.orm = 'Drizzle';
162
+ patterns.type = 'SQL';
163
+ } else if (files.some(file => file.includes('typeorm') || file.endsWith('.entity.ts'))) {
164
+ patterns.orm = 'TypeORM';
165
+ patterns.type = 'SQL';
166
+ } else if (files.some(file => file.includes('sequelize'))) {
167
+ patterns.orm = 'Sequelize';
168
+ patterns.type = 'SQL';
169
+ } else if (files.some(file => file.includes('mongoose'))) {
170
+ patterns.orm = 'Mongoose';
171
+ patterns.type = 'NoSQL';
172
+ }
173
+
174
+ // Check for migrations
175
+ patterns.migrations = files.some(file =>
176
+ file.includes('/migrations/') ||
177
+ file.includes('migrate')
178
+ );
179
+
180
+ if (dbFiles.length === 0 && !patterns.orm) {
181
+ return { detected: false };
182
+ }
183
+
184
+ return {
185
+ detected: true,
186
+ orm: patterns.orm,
187
+ type: patterns.type,
188
+ migrations: patterns.migrations,
189
+ files: dbFiles.length,
190
+ examples: dbFiles.slice(0, 3).map(f => path.basename(f))
191
+ };
192
+ }
193
+
194
+ /**
195
+ * Detect test patterns
196
+ *
197
+ * @param {string[]} files - Array of file paths
198
+ * @param {string} projectRoot - Absolute path to project root
199
+ * @returns {Promise<Object>} Test pattern detection result
200
+ */
201
+ export async function detectTestPatterns(files, projectRoot) {
202
+ const testFiles = files.filter(file =>
203
+ /\.(test|spec)\.(js|ts|jsx|tsx)$/.test(file) ||
204
+ file.includes('/tests/') ||
205
+ file.includes('/__tests__/') ||
206
+ file.includes('/test/')
207
+ );
208
+
209
+ if (testFiles.length === 0) {
210
+ return { detected: false };
211
+ }
212
+
213
+ const patterns = {
214
+ unit: 0,
215
+ integration: 0,
216
+ e2e: 0
217
+ };
218
+
219
+ // Categorize tests by directory
220
+ for (const file of testFiles) {
221
+ if (file.includes('/unit/') || file.includes('.unit.')) {
222
+ patterns.unit++;
223
+ } else if (file.includes('/integration/') || file.includes('.integration.')) {
224
+ patterns.integration++;
225
+ } else if (file.includes('/e2e/') || file.includes('.e2e.') || file.includes('cypress/') || file.includes('playwright/')) {
226
+ patterns.e2e++;
227
+ } else {
228
+ // Default to unit tests
229
+ patterns.unit++;
230
+ }
231
+ }
232
+
233
+ // Detect test framework from file content
234
+ let framework = 'unknown';
235
+ try {
236
+ const sampleFile = path.join(projectRoot, testFiles[0]);
237
+ const content = await fs.readFile(sampleFile, 'utf-8');
238
+
239
+ if (content.includes('vitest') || content.includes('describe.only')) {
240
+ framework = 'vitest';
241
+ } else if (content.includes('jest') || content.includes('@jest')) {
242
+ framework = 'jest';
243
+ } else if (content.includes('mocha') || content.includes('chai')) {
244
+ framework = 'mocha';
245
+ } else if (content.includes('cypress')) {
246
+ framework = 'cypress';
247
+ } else if (content.includes('playwright')) {
248
+ framework = 'playwright';
249
+ } else if (/describe\(|it\(|test\(/.test(content)) {
250
+ framework = 'jest'; // Default assumption
251
+ }
252
+ } catch (error) {
253
+ // Can't read file, framework remains unknown
254
+ }
255
+
256
+ return {
257
+ detected: true,
258
+ framework,
259
+ count: testFiles.length,
260
+ types: {
261
+ unit: patterns.unit,
262
+ integration: patterns.integration,
263
+ e2e: patterns.e2e
264
+ },
265
+ coverage: files.some(file => file.includes('coverage/')) || files.some(file => file.includes('.coverage'))
266
+ };
267
+ }
268
+
269
+ /**
270
+ * Detect authentication patterns
271
+ *
272
+ * @param {string[]} files - Array of file paths
273
+ * @param {string} projectRoot - Absolute path to project root
274
+ * @returns {Promise<Object>} Auth pattern detection result
275
+ */
276
+ export async function detectAuthPatterns(files, projectRoot) {
277
+ const authFiles = files.filter(file =>
278
+ file.includes('/auth/') ||
279
+ file.includes('authentication') ||
280
+ file.includes('login') ||
281
+ file.includes('session') ||
282
+ file.includes('jwt') ||
283
+ file.includes('oauth')
284
+ );
285
+
286
+ if (authFiles.length === 0) {
287
+ return { detected: false };
288
+ }
289
+
290
+ const patterns = {
291
+ jwt: false,
292
+ oauth: false,
293
+ sessions: false,
294
+ nextAuth: false
295
+ };
296
+
297
+ // Check for specific auth patterns
298
+ patterns.jwt = authFiles.some(file =>
299
+ file.includes('jwt') || file.includes('token')
300
+ );
301
+
302
+ patterns.oauth = authFiles.some(file =>
303
+ file.includes('oauth') || file.includes('passport')
304
+ );
305
+
306
+ patterns.sessions = authFiles.some(file =>
307
+ file.includes('session')
308
+ );
309
+
310
+ patterns.nextAuth = files.some(file =>
311
+ file.includes('next-auth') || file.includes('[...nextauth]')
312
+ );
313
+
314
+ return {
315
+ detected: true,
316
+ methods: Object.entries(patterns)
317
+ .filter(([_, detected]) => detected)
318
+ .map(([method]) => method),
319
+ files: authFiles.length,
320
+ examples: authFiles.slice(0, 3).map(f => path.basename(f))
321
+ };
322
+ }
323
+
324
+ /**
325
+ * Detect all patterns in project
326
+ *
327
+ * @param {string[]} files - Array of file paths
328
+ * @param {string} projectRoot - Absolute path to project root
329
+ * @returns {Promise<Object>} All detected patterns
330
+ */
331
+ export async function detectPatterns(files, projectRoot) {
332
+ const [components, api, database, tests, auth] = await Promise.all([
333
+ detectComponentPatterns(files, projectRoot),
334
+ detectAPIPatterns(files, projectRoot),
335
+ detectDatabasePatterns(files, projectRoot),
336
+ detectTestPatterns(files, projectRoot),
337
+ detectAuthPatterns(files, projectRoot)
338
+ ]);
339
+
340
+ return {
341
+ components,
342
+ api,
343
+ database,
344
+ tests,
345
+ auth
346
+ };
347
+ }
348
+
349
+ export default {
350
+ detectPatterns,
351
+ detectComponentPatterns,
352
+ detectAPIPatterns,
353
+ detectDatabasePatterns,
354
+ detectTestPatterns,
355
+ detectAuthPatterns
356
+ };