agileflow 3.3.0 → 3.4.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 (121) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +6 -6
  3. package/lib/skill-loader.js +0 -1
  4. package/package.json +1 -1
  5. package/scripts/agileflow-statusline.sh +81 -0
  6. package/scripts/claude-tmux.sh +113 -22
  7. package/scripts/claude-watchdog.sh +225 -0
  8. package/scripts/generators/agent-registry.js +14 -1
  9. package/scripts/generators/inject-babysit.js +22 -9
  10. package/scripts/generators/inject-help.js +19 -9
  11. package/scripts/lib/audit-cleanup.js +250 -0
  12. package/scripts/lib/audit-registry.js +248 -0
  13. package/scripts/lib/feature-catalog.js +3 -3
  14. package/scripts/lib/gate-enforcer.js +295 -0
  15. package/scripts/lib/model-profiles.js +98 -0
  16. package/scripts/lib/signal-detectors.js +1 -1
  17. package/scripts/lib/skill-catalog.js +557 -0
  18. package/scripts/lib/skill-recommender.js +311 -0
  19. package/scripts/lib/tdd-phase-manager.js +455 -0
  20. package/scripts/lib/team-events.js +34 -3
  21. package/scripts/lib/tmux-group-colors.js +113 -0
  22. package/scripts/messaging-bridge.js +209 -1
  23. package/scripts/spawn-audit-sessions.js +549 -0
  24. package/scripts/team-manager.js +37 -16
  25. package/scripts/tmux-close-windows.sh +180 -0
  26. package/src/core/agents/ads-audit-budget.md +181 -0
  27. package/src/core/agents/ads-audit-compliance.md +169 -0
  28. package/src/core/agents/ads-audit-creative.md +164 -0
  29. package/src/core/agents/ads-audit-google.md +226 -0
  30. package/src/core/agents/ads-audit-meta.md +183 -0
  31. package/src/core/agents/ads-audit-tracking.md +197 -0
  32. package/src/core/agents/ads-consensus.md +322 -0
  33. package/src/core/agents/brainstorm-analyzer-features.md +169 -0
  34. package/src/core/agents/brainstorm-analyzer-growth.md +161 -0
  35. package/src/core/agents/brainstorm-analyzer-integration.md +172 -0
  36. package/src/core/agents/brainstorm-analyzer-market.md +147 -0
  37. package/src/core/agents/brainstorm-analyzer-ux.md +167 -0
  38. package/src/core/agents/brainstorm-consensus.md +237 -0
  39. package/src/core/agents/completeness-consensus.md +5 -5
  40. package/src/core/agents/perf-consensus.md +2 -2
  41. package/src/core/agents/security-consensus.md +2 -2
  42. package/src/core/agents/seo-analyzer-content.md +167 -0
  43. package/src/core/agents/seo-analyzer-images.md +187 -0
  44. package/src/core/agents/seo-analyzer-performance.md +206 -0
  45. package/src/core/agents/seo-analyzer-schema.md +176 -0
  46. package/src/core/agents/seo-analyzer-sitemap.md +172 -0
  47. package/src/core/agents/seo-analyzer-technical.md +144 -0
  48. package/src/core/agents/seo-consensus.md +289 -0
  49. package/src/core/agents/test-consensus.md +2 -2
  50. package/src/core/commands/ads/audit.md +375 -0
  51. package/src/core/commands/ads/budget.md +97 -0
  52. package/src/core/commands/ads/competitor.md +112 -0
  53. package/src/core/commands/ads/creative.md +85 -0
  54. package/src/core/commands/ads/google.md +112 -0
  55. package/src/core/commands/ads/landing.md +119 -0
  56. package/src/core/commands/ads/linkedin.md +112 -0
  57. package/src/core/commands/ads/meta.md +91 -0
  58. package/src/core/commands/ads/microsoft.md +115 -0
  59. package/src/core/commands/ads/plan.md +321 -0
  60. package/src/core/commands/ads/tiktok.md +129 -0
  61. package/src/core/commands/ads/youtube.md +124 -0
  62. package/src/core/commands/ads.md +128 -0
  63. package/src/core/commands/babysit.md +249 -1284
  64. package/src/core/commands/{audit → code}/completeness.md +35 -25
  65. package/src/core/commands/{audit → code}/legal.md +26 -16
  66. package/src/core/commands/{audit → code}/logic.md +27 -16
  67. package/src/core/commands/{audit → code}/performance.md +30 -20
  68. package/src/core/commands/{audit → code}/security.md +32 -19
  69. package/src/core/commands/{audit → code}/test.md +30 -20
  70. package/src/core/commands/{discovery → ideate}/brief.md +12 -12
  71. package/src/core/commands/{discovery/new.md → ideate/discover.md} +13 -13
  72. package/src/core/commands/ideate/features.md +435 -0
  73. package/src/core/commands/seo/audit.md +373 -0
  74. package/src/core/commands/seo/competitor.md +174 -0
  75. package/src/core/commands/seo/content.md +107 -0
  76. package/src/core/commands/seo/geo.md +229 -0
  77. package/src/core/commands/seo/hreflang.md +140 -0
  78. package/src/core/commands/seo/images.md +96 -0
  79. package/src/core/commands/seo/page.md +198 -0
  80. package/src/core/commands/seo/plan.md +163 -0
  81. package/src/core/commands/seo/programmatic.md +131 -0
  82. package/src/core/commands/seo/references/cwv-thresholds.md +64 -0
  83. package/src/core/commands/seo/references/eeat-framework.md +110 -0
  84. package/src/core/commands/seo/references/quality-gates.md +91 -0
  85. package/src/core/commands/seo/references/schema-types.md +102 -0
  86. package/src/core/commands/seo/schema.md +183 -0
  87. package/src/core/commands/seo/sitemap.md +97 -0
  88. package/src/core/commands/seo/technical.md +100 -0
  89. package/src/core/commands/seo.md +107 -0
  90. package/src/core/commands/skill/list.md +68 -212
  91. package/src/core/commands/skill/recommend.md +216 -0
  92. package/src/core/commands/tdd-next.md +238 -0
  93. package/src/core/commands/tdd.md +210 -0
  94. package/src/core/experts/_core-expertise.yaml +105 -0
  95. package/src/core/experts/analytics/expertise.yaml +5 -99
  96. package/src/core/experts/codebase-query/expertise.yaml +3 -72
  97. package/src/core/experts/compliance/expertise.yaml +6 -72
  98. package/src/core/experts/database/expertise.yaml +9 -52
  99. package/src/core/experts/documentation/expertise.yaml +7 -140
  100. package/src/core/experts/integrations/expertise.yaml +7 -127
  101. package/src/core/experts/mentor/expertise.yaml +8 -35
  102. package/src/core/experts/monitoring/expertise.yaml +7 -49
  103. package/src/core/experts/performance/expertise.yaml +1 -26
  104. package/src/core/experts/security/expertise.yaml +9 -34
  105. package/src/core/experts/ui/expertise.yaml +6 -36
  106. package/src/core/knowledge/ads/ad-audit-checklist-scoring.md +424 -0
  107. package/src/core/knowledge/ads/ad-optimization-logic.md +590 -0
  108. package/src/core/knowledge/ads/ad-technical-specifications.md +385 -0
  109. package/src/core/knowledge/ads/definitive-advertising-reference-2026.md +506 -0
  110. package/src/core/knowledge/ads/paid-advertising-research-2026.md +445 -0
  111. package/src/core/templates/agileflow-metadata.json +15 -1
  112. package/tools/cli/installers/ide/_base-ide.js +42 -5
  113. package/tools/cli/installers/ide/claude-code.js +3 -3
  114. package/tools/cli/lib/content-injector.js +160 -12
  115. package/tools/cli/lib/docs-setup.js +1 -1
  116. package/src/core/commands/skill/create.md +0 -698
  117. package/src/core/commands/skill/delete.md +0 -316
  118. package/src/core/commands/skill/edit.md +0 -359
  119. package/src/core/commands/skill/test.md +0 -394
  120. package/src/core/commands/skill/upgrade.md +0 -552
  121. package/src/core/templates/skill-template.md +0 -117
@@ -0,0 +1,311 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * skill-recommender.js
4
+ *
5
+ * Tech stack detector + recommendation engine for skills.
6
+ * Reads package.json (or other project files) to detect the framework,
7
+ * styling, testing, database, and language. Maps detected stack to
8
+ * curated skills from skills.sh.
9
+ *
10
+ * Follows the signal-detectors.js pattern (detector functions returning recommendations).
11
+ */
12
+
13
+ 'use strict';
14
+
15
+ const fs = require('fs');
16
+ const path = require('path');
17
+ const { getAllCuratedSkills } = require('./skill-catalog');
18
+
19
+ // =============================================================================
20
+ // Tech Stack Detection
21
+ // =============================================================================
22
+
23
+ /**
24
+ * Detect project tech stack from package.json and project files.
25
+ * @param {string} projectRoot - Project root directory
26
+ * @returns {Object} Detected stack with categories
27
+ */
28
+ function detectTechStack(projectRoot) {
29
+ const stack = {
30
+ frameworks: [],
31
+ styling: [],
32
+ testing: [],
33
+ databases: [],
34
+ languages: [],
35
+ devops: [],
36
+ security: [],
37
+ };
38
+
39
+ // Read package.json
40
+ const pkgPath = path.join(projectRoot, 'package.json');
41
+ let pkg = null;
42
+ if (fs.existsSync(pkgPath)) {
43
+ try {
44
+ pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
45
+ } catch {
46
+ // Ignore parse errors
47
+ }
48
+ }
49
+
50
+ if (pkg) {
51
+ const allDeps = {
52
+ ...pkg.dependencies,
53
+ ...pkg.devDependencies,
54
+ };
55
+
56
+ // Framework detection
57
+ if (allDeps.next) stack.frameworks.push('next', 'react');
58
+ else if (allDeps.react) stack.frameworks.push('react');
59
+ if (allDeps.vue || allDeps['vue-router']) stack.frameworks.push('vue');
60
+ if (allDeps.svelte || allDeps['@sveltejs/kit']) stack.frameworks.push('svelte', 'sveltekit');
61
+ if (allDeps['@angular/core']) stack.frameworks.push('angular');
62
+ if (allDeps.express) stack.frameworks.push('express', 'node');
63
+ if (allDeps.fastify) stack.frameworks.push('fastify', 'node');
64
+ if (allDeps.hono) stack.frameworks.push('hono', 'node');
65
+ if (allDeps['react-native'] || allDeps.expo) stack.frameworks.push('react-native', 'mobile');
66
+ if (allDeps.nuxt) stack.frameworks.push('nuxt', 'vue');
67
+ if (allDeps.astro) stack.frameworks.push('astro');
68
+ if (allDeps.remix || allDeps['@remix-run/react']) stack.frameworks.push('remix', 'react');
69
+
70
+ // Styling detection
71
+ if (allDeps.tailwindcss) stack.styling.push('tailwind', 'tailwindcss');
72
+ if (allDeps['styled-components']) stack.styling.push('styled-components');
73
+ if (allDeps['@emotion/react']) stack.styling.push('emotion');
74
+ if (allDeps.sass) stack.styling.push('sass');
75
+
76
+ // Testing detection
77
+ if (allDeps.jest) stack.testing.push('jest');
78
+ if (allDeps.vitest) stack.testing.push('vitest', 'vite');
79
+ if (allDeps.playwright || allDeps['@playwright/test']) stack.testing.push('playwright', 'e2e');
80
+ if (allDeps.cypress) stack.testing.push('cypress', 'e2e');
81
+ if (allDeps.mocha) stack.testing.push('mocha');
82
+
83
+ // Database detection
84
+ if (allDeps.prisma || allDeps['@prisma/client']) stack.databases.push('prisma', 'orm');
85
+ if (allDeps['@supabase/supabase-js']) stack.databases.push('supabase', 'postgres');
86
+ if (allDeps.mongoose || allDeps.mongodb) stack.databases.push('mongodb', 'nosql');
87
+ if (allDeps.pg || allDeps.postgres) stack.databases.push('postgresql', 'postgres');
88
+ if (allDeps.redis || allDeps.ioredis) stack.databases.push('redis', 'cache');
89
+ if (allDeps.drizzle || allDeps['drizzle-orm']) stack.databases.push('drizzle', 'orm');
90
+ if (allDeps.knex) stack.databases.push('knex', 'sql');
91
+ if (allDeps.sequelize) stack.databases.push('sequelize', 'orm');
92
+ if (allDeps.typeorm) stack.databases.push('typeorm', 'orm');
93
+
94
+ // Language detection
95
+ if (allDeps.typescript) stack.languages.push('typescript', 'ts');
96
+ if (allDeps['@apollo/server'] || allDeps['@apollo/client'] || allDeps.graphql) {
97
+ stack.frameworks.push('graphql', 'apollo');
98
+ }
99
+
100
+ // DevOps detection
101
+ if (allDeps.docker || fs.existsSync(path.join(projectRoot, 'Dockerfile'))) {
102
+ stack.devops.push('docker', 'containers');
103
+ }
104
+ if (fs.existsSync(path.join(projectRoot, '.github', 'workflows'))) {
105
+ stack.devops.push('github-actions', 'ci');
106
+ }
107
+ if (allDeps['socket.io'] || allDeps.ws) stack.frameworks.push('websocket', 'real-time');
108
+ }
109
+
110
+ // Python detection
111
+ const pyFiles = ['requirements.txt', 'pyproject.toml', 'setup.py', 'Pipfile'];
112
+ for (const f of pyFiles) {
113
+ if (fs.existsSync(path.join(projectRoot, f))) {
114
+ stack.languages.push('python');
115
+
116
+ // Check for specific Python frameworks
117
+ try {
118
+ const content = fs.readFileSync(path.join(projectRoot, f), 'utf8');
119
+ if (content.includes('fastapi')) stack.frameworks.push('fastapi', 'python');
120
+ if (content.includes('django')) stack.frameworks.push('django', 'python');
121
+ if (content.includes('flask')) stack.frameworks.push('flask', 'python');
122
+ if (content.includes('pytest')) stack.testing.push('pytest');
123
+ if (content.includes('pydantic')) stack.frameworks.push('pydantic');
124
+ } catch {
125
+ // Ignore read errors
126
+ }
127
+ break;
128
+ }
129
+ }
130
+
131
+ // Go detection
132
+ if (fs.existsSync(path.join(projectRoot, 'go.mod'))) {
133
+ stack.languages.push('go', 'golang');
134
+ stack.frameworks.push('go-backend');
135
+ }
136
+
137
+ // PHP detection
138
+ if (fs.existsSync(path.join(projectRoot, 'composer.json'))) {
139
+ stack.languages.push('php');
140
+ }
141
+
142
+ // Docker/K8s detection
143
+ if (fs.existsSync(path.join(projectRoot, 'Dockerfile'))) {
144
+ stack.devops.push('docker');
145
+ }
146
+ if (
147
+ fs.existsSync(path.join(projectRoot, 'k8s')) ||
148
+ fs.existsSync(path.join(projectRoot, 'kubernetes'))
149
+ ) {
150
+ stack.devops.push('kubernetes', 'k8s');
151
+ }
152
+ if (
153
+ fs.existsSync(path.join(projectRoot, 'terraform')) ||
154
+ fs.existsSync(path.join(projectRoot, 'main.tf'))
155
+ ) {
156
+ stack.devops.push('terraform', 'iac');
157
+ }
158
+ if (fs.existsSync(path.join(projectRoot, 'vercel.json'))) {
159
+ stack.devops.push('vercel', 'deployment');
160
+ }
161
+
162
+ // Deduplicate all arrays
163
+ for (const key of Object.keys(stack)) {
164
+ stack[key] = [...new Set(stack[key])];
165
+ }
166
+
167
+ return stack;
168
+ }
169
+
170
+ // =============================================================================
171
+ // Recommendation Engine
172
+ // =============================================================================
173
+
174
+ /**
175
+ * Score a skill against detected tech stack.
176
+ * @param {Object} skill - Curated skill entry
177
+ * @param {Object} stack - Detected tech stack
178
+ * @returns {number} Relevance score (0-100)
179
+ */
180
+ function scoreSkill(skill, stack) {
181
+ const allTags = [
182
+ ...stack.frameworks,
183
+ ...stack.styling,
184
+ ...stack.testing,
185
+ ...stack.databases,
186
+ ...stack.languages,
187
+ ...stack.devops,
188
+ ...stack.security,
189
+ ];
190
+
191
+ if (allTags.length === 0) return 0;
192
+
193
+ let matchCount = 0;
194
+ for (const tag of skill.tags) {
195
+ if (allTags.includes(tag)) {
196
+ matchCount++;
197
+ }
198
+ }
199
+
200
+ if (matchCount === 0) return 0;
201
+
202
+ // Score: percentage of skill tags that match, weighted by total matches
203
+ const tagCoverage = matchCount / skill.tags.length;
204
+ return Math.round(tagCoverage * 100);
205
+ }
206
+
207
+ /**
208
+ * Get skill recommendations based on detected tech stack.
209
+ * @param {string} projectRoot - Project root directory
210
+ * @param {Object} [options] - Options
211
+ * @param {string[]} [options.installedSkills] - Names of already-installed skills to filter out
212
+ * @param {number} [options.minScore] - Minimum relevance score (default: 20)
213
+ * @param {number} [options.maxResults] - Maximum results per category (default: 5)
214
+ * @returns {Object} Recommendations with stack info and ranked skills
215
+ */
216
+ function getRecommendations(projectRoot, options = {}) {
217
+ const { installedSkills = [], minScore = 20, maxResults = 5 } = options;
218
+
219
+ const stack = detectTechStack(projectRoot);
220
+ const allSkills = getAllCuratedSkills();
221
+ const installedSet = new Set(installedSkills.map(n => n.toLowerCase()));
222
+
223
+ // Score all skills
224
+ const scored = allSkills
225
+ .map(skill => ({
226
+ ...skill,
227
+ score: scoreSkill(skill, stack),
228
+ installed: installedSet.has(skill.name.toLowerCase()),
229
+ }))
230
+ .filter(s => s.score >= minScore && !s.installed)
231
+ .sort((a, b) => b.score - a.score);
232
+
233
+ // Group by category with limits
234
+ const byCategory = {};
235
+ for (const skill of scored) {
236
+ if (!byCategory[skill.category]) {
237
+ byCategory[skill.category] = [];
238
+ }
239
+ if (byCategory[skill.category].length < maxResults) {
240
+ byCategory[skill.category].push(skill);
241
+ }
242
+ }
243
+
244
+ return {
245
+ stack,
246
+ recommendations: byCategory,
247
+ totalMatches: scored.length,
248
+ };
249
+ }
250
+
251
+ /**
252
+ * Format recommendations as a display string.
253
+ * @param {Object} result - Result from getRecommendations
254
+ * @returns {string} Formatted display text
255
+ */
256
+ function formatRecommendations(result) {
257
+ const { stack, recommendations, totalMatches } = result;
258
+
259
+ const lines = [];
260
+
261
+ // Show detected stack
262
+ const detected = [];
263
+ if (stack.frameworks.length) detected.push(`Frameworks: ${stack.frameworks.join(', ')}`);
264
+ if (stack.languages.length) detected.push(`Languages: ${stack.languages.join(', ')}`);
265
+ if (stack.databases.length) detected.push(`Databases: ${stack.databases.join(', ')}`);
266
+ if (stack.testing.length) detected.push(`Testing: ${stack.testing.join(', ')}`);
267
+ if (stack.styling.length) detected.push(`Styling: ${stack.styling.join(', ')}`);
268
+ if (stack.devops.length) detected.push(`DevOps: ${stack.devops.join(', ')}`);
269
+
270
+ if (detected.length > 0) {
271
+ lines.push('**Detected Tech Stack:**');
272
+ for (const d of detected) {
273
+ lines.push(`- ${d}`);
274
+ }
275
+ lines.push('');
276
+ }
277
+
278
+ // Show recommendations by category
279
+ const categories = Object.keys(recommendations);
280
+ if (categories.length === 0) {
281
+ lines.push('No matching skills found for your tech stack.');
282
+ lines.push('Browse the full marketplace: `npx skills find`');
283
+ return lines.join('\n');
284
+ }
285
+
286
+ lines.push(`**Recommended Skills (${totalMatches} matches):**`);
287
+ lines.push('');
288
+
289
+ for (const category of categories) {
290
+ const skills = recommendations[category];
291
+ lines.push(`### ${category}`);
292
+ lines.push('');
293
+ for (const s of skills) {
294
+ lines.push(`- **${s.name}** (${s.score}% match) - ${s.description}`);
295
+ lines.push(` Install: \`${s.installCmd}\``);
296
+ }
297
+ lines.push('');
298
+ }
299
+
300
+ lines.push('---');
301
+ lines.push('Browse more: `npx skills find`');
302
+
303
+ return lines.join('\n');
304
+ }
305
+
306
+ module.exports = {
307
+ detectTechStack,
308
+ scoreSkill,
309
+ getRecommendations,
310
+ formatRecommendations,
311
+ };