agileflow 3.2.1 → 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 (134) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +6 -6
  3. package/lib/feature-flags.js +32 -4
  4. package/lib/skill-loader.js +0 -1
  5. package/package.json +1 -1
  6. package/scripts/agileflow-statusline.sh +81 -0
  7. package/scripts/babysit-clear-restore.js +154 -0
  8. package/scripts/claude-tmux.sh +120 -24
  9. package/scripts/claude-watchdog.sh +225 -0
  10. package/scripts/generators/agent-registry.js +14 -1
  11. package/scripts/generators/inject-babysit.js +22 -9
  12. package/scripts/generators/inject-help.js +19 -9
  13. package/scripts/lib/README-portable-tasks.md +424 -0
  14. package/scripts/lib/audit-cleanup.js +250 -0
  15. package/scripts/lib/audit-registry.js +248 -0
  16. package/scripts/lib/configure-detect.js +20 -0
  17. package/scripts/lib/feature-catalog.js +13 -2
  18. package/scripts/lib/gate-enforcer.js +295 -0
  19. package/scripts/lib/model-profiles.js +98 -0
  20. package/scripts/lib/signal-detectors.js +1 -1
  21. package/scripts/lib/skill-catalog.js +557 -0
  22. package/scripts/lib/skill-recommender.js +311 -0
  23. package/scripts/lib/tdd-phase-manager.js +455 -0
  24. package/scripts/lib/team-events.js +76 -8
  25. package/scripts/lib/tmux-group-colors.js +113 -0
  26. package/scripts/messaging-bridge.js +209 -1
  27. package/scripts/spawn-audit-sessions.js +549 -0
  28. package/scripts/team-manager.js +37 -16
  29. package/scripts/tmux-close-windows.sh +180 -0
  30. package/scripts/tmux-restore-window.sh +67 -0
  31. package/scripts/tmux-save-closed-window.sh +35 -0
  32. package/src/core/agents/ads-audit-budget.md +181 -0
  33. package/src/core/agents/ads-audit-compliance.md +169 -0
  34. package/src/core/agents/ads-audit-creative.md +164 -0
  35. package/src/core/agents/ads-audit-google.md +226 -0
  36. package/src/core/agents/ads-audit-meta.md +183 -0
  37. package/src/core/agents/ads-audit-tracking.md +197 -0
  38. package/src/core/agents/ads-consensus.md +322 -0
  39. package/src/core/agents/brainstorm-analyzer-features.md +169 -0
  40. package/src/core/agents/brainstorm-analyzer-growth.md +161 -0
  41. package/src/core/agents/brainstorm-analyzer-integration.md +172 -0
  42. package/src/core/agents/brainstorm-analyzer-market.md +147 -0
  43. package/src/core/agents/brainstorm-analyzer-ux.md +167 -0
  44. package/src/core/agents/brainstorm-consensus.md +237 -0
  45. package/src/core/agents/completeness-analyzer-api.md +190 -0
  46. package/src/core/agents/completeness-analyzer-conditional.md +201 -0
  47. package/src/core/agents/completeness-analyzer-handlers.md +159 -0
  48. package/src/core/agents/completeness-analyzer-imports.md +159 -0
  49. package/src/core/agents/completeness-analyzer-routes.md +182 -0
  50. package/src/core/agents/completeness-analyzer-state.md +188 -0
  51. package/src/core/agents/completeness-analyzer-stubs.md +198 -0
  52. package/src/core/agents/completeness-consensus.md +286 -0
  53. package/src/core/agents/perf-consensus.md +2 -2
  54. package/src/core/agents/security-consensus.md +2 -2
  55. package/src/core/agents/seo-analyzer-content.md +167 -0
  56. package/src/core/agents/seo-analyzer-images.md +187 -0
  57. package/src/core/agents/seo-analyzer-performance.md +206 -0
  58. package/src/core/agents/seo-analyzer-schema.md +176 -0
  59. package/src/core/agents/seo-analyzer-sitemap.md +172 -0
  60. package/src/core/agents/seo-analyzer-technical.md +144 -0
  61. package/src/core/agents/seo-consensus.md +289 -0
  62. package/src/core/agents/test-consensus.md +2 -2
  63. package/src/core/commands/ads/audit.md +375 -0
  64. package/src/core/commands/ads/budget.md +97 -0
  65. package/src/core/commands/ads/competitor.md +112 -0
  66. package/src/core/commands/ads/creative.md +85 -0
  67. package/src/core/commands/ads/google.md +112 -0
  68. package/src/core/commands/ads/landing.md +119 -0
  69. package/src/core/commands/ads/linkedin.md +112 -0
  70. package/src/core/commands/ads/meta.md +91 -0
  71. package/src/core/commands/ads/microsoft.md +115 -0
  72. package/src/core/commands/ads/plan.md +321 -0
  73. package/src/core/commands/ads/tiktok.md +129 -0
  74. package/src/core/commands/ads/youtube.md +124 -0
  75. package/src/core/commands/ads.md +128 -0
  76. package/src/core/commands/babysit.md +250 -1344
  77. package/src/core/commands/code/completeness.md +466 -0
  78. package/src/core/commands/{audit → code}/legal.md +26 -16
  79. package/src/core/commands/{audit → code}/logic.md +27 -16
  80. package/src/core/commands/{audit → code}/performance.md +30 -20
  81. package/src/core/commands/{audit → code}/security.md +32 -19
  82. package/src/core/commands/{audit → code}/test.md +30 -20
  83. package/src/core/commands/{discovery → ideate}/brief.md +12 -12
  84. package/src/core/commands/{discovery/new.md → ideate/discover.md} +13 -13
  85. package/src/core/commands/ideate/features.md +435 -0
  86. package/src/core/commands/seo/audit.md +373 -0
  87. package/src/core/commands/seo/competitor.md +174 -0
  88. package/src/core/commands/seo/content.md +107 -0
  89. package/src/core/commands/seo/geo.md +229 -0
  90. package/src/core/commands/seo/hreflang.md +140 -0
  91. package/src/core/commands/seo/images.md +96 -0
  92. package/src/core/commands/seo/page.md +198 -0
  93. package/src/core/commands/seo/plan.md +163 -0
  94. package/src/core/commands/seo/programmatic.md +131 -0
  95. package/src/core/commands/seo/references/cwv-thresholds.md +64 -0
  96. package/src/core/commands/seo/references/eeat-framework.md +110 -0
  97. package/src/core/commands/seo/references/quality-gates.md +91 -0
  98. package/src/core/commands/seo/references/schema-types.md +102 -0
  99. package/src/core/commands/seo/schema.md +183 -0
  100. package/src/core/commands/seo/sitemap.md +97 -0
  101. package/src/core/commands/seo/technical.md +100 -0
  102. package/src/core/commands/seo.md +107 -0
  103. package/src/core/commands/skill/list.md +68 -212
  104. package/src/core/commands/skill/recommend.md +216 -0
  105. package/src/core/commands/tdd-next.md +238 -0
  106. package/src/core/commands/tdd.md +210 -0
  107. package/src/core/experts/_core-expertise.yaml +105 -0
  108. package/src/core/experts/analytics/expertise.yaml +5 -99
  109. package/src/core/experts/codebase-query/expertise.yaml +3 -72
  110. package/src/core/experts/compliance/expertise.yaml +6 -72
  111. package/src/core/experts/database/expertise.yaml +9 -52
  112. package/src/core/experts/documentation/expertise.yaml +7 -140
  113. package/src/core/experts/integrations/expertise.yaml +7 -127
  114. package/src/core/experts/mentor/expertise.yaml +8 -35
  115. package/src/core/experts/monitoring/expertise.yaml +7 -49
  116. package/src/core/experts/performance/expertise.yaml +1 -26
  117. package/src/core/experts/security/expertise.yaml +9 -34
  118. package/src/core/experts/ui/expertise.yaml +6 -36
  119. package/src/core/knowledge/ads/ad-audit-checklist-scoring.md +424 -0
  120. package/src/core/knowledge/ads/ad-optimization-logic.md +590 -0
  121. package/src/core/knowledge/ads/ad-technical-specifications.md +385 -0
  122. package/src/core/knowledge/ads/definitive-advertising-reference-2026.md +506 -0
  123. package/src/core/knowledge/ads/paid-advertising-research-2026.md +445 -0
  124. package/src/core/templates/agileflow-metadata.json +15 -1
  125. package/tools/cli/installers/ide/_base-ide.js +42 -5
  126. package/tools/cli/installers/ide/claude-code.js +13 -4
  127. package/tools/cli/lib/content-injector.js +160 -12
  128. package/tools/cli/lib/docs-setup.js +1 -1
  129. package/src/core/commands/skill/create.md +0 -698
  130. package/src/core/commands/skill/delete.md +0 -316
  131. package/src/core/commands/skill/edit.md +0 -359
  132. package/src/core/commands/skill/test.md +0 -394
  133. package/src/core/commands/skill/upgrade.md +0 -552
  134. 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
+ };