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,295 @@
1
+ /**
2
+ * gate-enforcer.js - Workflow Gate Enforcement for Babysit Strict Mode
3
+ *
4
+ * Filters AskUserQuestion options based on workflow gate status.
5
+ * When STRICT=true in babysit, certain options are removed or blocked
6
+ * based on whether gates have been satisfied (tests passed, review done, etc.).
7
+ *
8
+ * Gates:
9
+ * - tests_passed: Must run and pass tests before commit
10
+ * - review_done: Must run code review for 5+ source files before commit
11
+ * - logic_audit_done: Must run logic audit before commit (advisory in non-strict)
12
+ *
13
+ * Usage:
14
+ * const { filterOptions, getGateStatus, updateGate } = require('./gate-enforcer');
15
+ * const filtered = filterOptions(options, gateState, { strict: true });
16
+ */
17
+
18
+ 'use strict';
19
+
20
+ // ============================================================================
21
+ // Constants
22
+ // ============================================================================
23
+
24
+ /**
25
+ * Gate types that can block workflow progression
26
+ */
27
+ const GATES = {
28
+ TESTS_PASSED: 'tests_passed',
29
+ REVIEW_DONE: 'review_done',
30
+ LOGIC_AUDIT_DONE: 'logic_audit_done',
31
+ };
32
+
33
+ /**
34
+ * Actions that require specific gates to be satisfied
35
+ */
36
+ const GATE_REQUIREMENTS = {
37
+ commit: {
38
+ strict: [GATES.TESTS_PASSED],
39
+ strict_5plus: [GATES.TESTS_PASSED, GATES.REVIEW_DONE],
40
+ },
41
+ next_story: {
42
+ strict: [GATES.TESTS_PASSED],
43
+ },
44
+ };
45
+
46
+ /**
47
+ * Patterns that identify commit-related options
48
+ */
49
+ const COMMIT_PATTERNS = [/^commit/i, /^git commit/i, /commit.*changes/i, /commit:?\s/i];
50
+
51
+ /**
52
+ * Patterns that identify "skip" options
53
+ */
54
+ const SKIP_PATTERNS = [/skip.*test/i, /skip.*review/i, /skip.*audit/i, /skip.*verif/i];
55
+
56
+ /**
57
+ * Patterns that identify "next story" options
58
+ */
59
+ const NEXT_STORY_PATTERNS = [/continue to/i, /next story/i, /move to.*US-/i];
60
+
61
+ // ============================================================================
62
+ // Gate State Management
63
+ // ============================================================================
64
+
65
+ /**
66
+ * Create initial gate state for a workflow session
67
+ * @param {Object} options
68
+ * @param {number} options.filesChanged - Number of source files modified
69
+ * @param {boolean} options.strict - Whether strict mode is enabled
70
+ * @returns {Object} Initial gate state
71
+ */
72
+ function createGateState(options = {}) {
73
+ const { filesChanged = 0, strict = false } = options;
74
+
75
+ return {
76
+ strict,
77
+ files_changed: filesChanged,
78
+ gates: {
79
+ [GATES.TESTS_PASSED]: false,
80
+ [GATES.REVIEW_DONE]: false,
81
+ [GATES.LOGIC_AUDIT_DONE]: false,
82
+ },
83
+ history: [],
84
+ created_at: new Date().toISOString(),
85
+ };
86
+ }
87
+
88
+ /**
89
+ * Update a gate's status
90
+ * @param {Object} gateState - Current gate state
91
+ * @param {string} gate - Gate name from GATES
92
+ * @param {boolean} passed - Whether the gate passed
93
+ * @param {Object} metadata - Additional info (e.g., test count, review findings)
94
+ * @returns {Object} Updated gate state
95
+ */
96
+ function updateGate(gateState, gate, passed, metadata = {}) {
97
+ if (!Object.values(GATES).includes(gate)) {
98
+ throw new Error(`Unknown gate: ${gate}. Valid: ${Object.values(GATES).join(', ')}`);
99
+ }
100
+
101
+ const updated = {
102
+ ...gateState,
103
+ gates: {
104
+ ...gateState.gates,
105
+ [gate]: passed,
106
+ },
107
+ history: [
108
+ ...gateState.history,
109
+ {
110
+ gate,
111
+ passed,
112
+ at: new Date().toISOString(),
113
+ ...metadata,
114
+ },
115
+ ],
116
+ };
117
+
118
+ return updated;
119
+ }
120
+
121
+ /**
122
+ * Check if all required gates for an action are satisfied
123
+ * @param {Object} gateState - Current gate state
124
+ * @param {string} action - Action to check ('commit', 'next_story')
125
+ * @returns {{ allowed: boolean, missing: string[] }}
126
+ */
127
+ function checkGates(gateState, action) {
128
+ if (!gateState.strict) {
129
+ return { allowed: true, missing: [] };
130
+ }
131
+
132
+ let requirements;
133
+ if (action === 'commit' && gateState.files_changed >= 5) {
134
+ requirements = GATE_REQUIREMENTS.commit.strict_5plus || [];
135
+ } else {
136
+ requirements = (GATE_REQUIREMENTS[action] && GATE_REQUIREMENTS[action].strict) || [];
137
+ }
138
+
139
+ const missing = requirements.filter(gate => !gateState.gates[gate]);
140
+
141
+ return {
142
+ allowed: missing.length === 0,
143
+ missing,
144
+ };
145
+ }
146
+
147
+ // ============================================================================
148
+ // Option Filtering
149
+ // ============================================================================
150
+
151
+ /**
152
+ * Check if an option label matches any pattern in a list
153
+ * @param {string} label - Option label text
154
+ * @param {RegExp[]} patterns - Patterns to match against
155
+ * @returns {boolean}
156
+ */
157
+ function matchesPattern(label, patterns) {
158
+ if (typeof label !== 'string') return false;
159
+ return patterns.some(p => p.test(label));
160
+ }
161
+
162
+ /**
163
+ * Filter AskUserQuestion options based on gate state
164
+ *
165
+ * In strict mode:
166
+ * - Remove "commit" options if tests haven't passed
167
+ * - Remove "commit" options if review not done (5+ files)
168
+ * - Remove "skip tests/review/audit" options
169
+ * - Add gate status hints to option descriptions
170
+ *
171
+ * In non-strict mode:
172
+ * - Options are returned unchanged (soft guidance only)
173
+ *
174
+ * @param {Object[]} options - AskUserQuestion options array
175
+ * @param {Object} gateState - Current gate state
176
+ * @returns {Object[]} Filtered options
177
+ */
178
+ function filterOptions(options, gateState) {
179
+ if (!Array.isArray(options)) return [];
180
+ if (!gateState || !gateState.strict) {
181
+ return options;
182
+ }
183
+
184
+ return options
185
+ .filter(opt => {
186
+ const label = opt.label || '';
187
+
188
+ // In strict mode, remove skip options entirely
189
+ if (matchesPattern(label, SKIP_PATTERNS)) {
190
+ return false;
191
+ }
192
+
193
+ // Check commit gates
194
+ if (matchesPattern(label, COMMIT_PATTERNS)) {
195
+ const { allowed } = checkGates(gateState, 'commit');
196
+ if (!allowed) {
197
+ return false;
198
+ }
199
+ }
200
+
201
+ // Check next story gates
202
+ if (matchesPattern(label, NEXT_STORY_PATTERNS)) {
203
+ const { allowed } = checkGates(gateState, 'next_story');
204
+ if (!allowed) {
205
+ return false;
206
+ }
207
+ }
208
+
209
+ return true;
210
+ })
211
+ .map(opt => {
212
+ // Add gate status hints to descriptions
213
+ const label = opt.label || '';
214
+
215
+ if (matchesPattern(label, COMMIT_PATTERNS) && gateState.strict) {
216
+ const checks = [];
217
+ if (gateState.gates[GATES.TESTS_PASSED]) checks.push('tests passed');
218
+ if (gateState.gates[GATES.REVIEW_DONE]) checks.push('review done');
219
+ if (gateState.gates[GATES.LOGIC_AUDIT_DONE]) checks.push('audit done');
220
+
221
+ if (checks.length > 0) {
222
+ return {
223
+ ...opt,
224
+ description: `${opt.description || ''} [Gates: ${checks.join(', ')}]`.trim(),
225
+ };
226
+ }
227
+ }
228
+
229
+ return opt;
230
+ });
231
+ }
232
+
233
+ /**
234
+ * Get a human-readable gate status summary
235
+ * @param {Object} gateState - Current gate state
236
+ * @returns {string} Status summary
237
+ */
238
+ function getGateStatusSummary(gateState) {
239
+ if (!gateState || !gateState.strict) {
240
+ return 'Strict mode: OFF (soft guidance)';
241
+ }
242
+
243
+ const lines = [`Strict mode: ON | ${gateState.files_changed} files changed`];
244
+
245
+ for (const [gate, passed] of Object.entries(gateState.gates)) {
246
+ const icon = passed ? '✅' : '⬜';
247
+ const name = gate.replace(/_/g, ' ');
248
+ lines.push(` ${icon} ${name}`);
249
+ }
250
+
251
+ return lines.join('\n');
252
+ }
253
+
254
+ /**
255
+ * Get blocking message for a failed gate check
256
+ * @param {string[]} missingGates - List of unsatisfied gates
257
+ * @returns {string} Human-readable blocking message
258
+ */
259
+ function getBlockingMessage(missingGates) {
260
+ const messages = {
261
+ [GATES.TESTS_PASSED]: 'Run tests first (tests must pass before committing)',
262
+ [GATES.REVIEW_DONE]: 'Run code review first (required for 5+ modified files)',
263
+ [GATES.LOGIC_AUDIT_DONE]: 'Run logic audit first',
264
+ };
265
+
266
+ return missingGates.map(gate => `🚫 ${messages[gate] || gate}`).join('\n');
267
+ }
268
+
269
+ // ============================================================================
270
+ // Exports
271
+ // ============================================================================
272
+
273
+ module.exports = {
274
+ // Constants
275
+ GATES,
276
+ GATE_REQUIREMENTS,
277
+
278
+ // State management
279
+ createGateState,
280
+ updateGate,
281
+ checkGates,
282
+
283
+ // Option filtering
284
+ filterOptions,
285
+ matchesPattern,
286
+
287
+ // Reporting
288
+ getGateStatusSummary,
289
+ getBlockingMessage,
290
+
291
+ // Patterns (for testing)
292
+ COMMIT_PATTERNS,
293
+ SKIP_PATTERNS,
294
+ NEXT_STORY_PATTERNS,
295
+ };
@@ -0,0 +1,98 @@
1
+ /**
2
+ * model-profiles.js - Model resolution for audit subagents
3
+ *
4
+ * Resolves which model (haiku/sonnet/opus) to use for agent subagents.
5
+ * Models are specified inline via command arguments (MODEL=opus).
6
+ *
7
+ * Resolution order:
8
+ * 1. Explicit MODEL= argument (highest priority)
9
+ * 2. Agent frontmatter model (from .md file)
10
+ * 3. Fallback: 'haiku'
11
+ *
12
+ * Usage:
13
+ * const { resolveModel, estimateCost } = require('./model-profiles');
14
+ * const model = resolveModel('opus', 'haiku'); // returns 'opus'
15
+ * const model2 = resolveModel(null, 'sonnet'); // returns 'sonnet'
16
+ * const model3 = resolveModel(null, null); // returns 'haiku'
17
+ */
18
+
19
+ const VALID_MODELS = ['haiku', 'sonnet', 'opus'];
20
+
21
+ /**
22
+ * Resolve which model to use for a given agent.
23
+ *
24
+ * Resolution order:
25
+ * 1. Explicit model argument (MODEL= from command)
26
+ * 2. Agent frontmatter model
27
+ * 3. Fallback: 'haiku'
28
+ *
29
+ * @param {string} [explicitModel] - MODEL= argument value
30
+ * @param {string} [frontmatterModel] - Model from agent .md frontmatter
31
+ * @returns {string} Model name: 'haiku', 'sonnet', or 'opus'
32
+ */
33
+ function resolveModel(explicitModel, frontmatterModel) {
34
+ // 1. Explicit MODEL= argument
35
+ if (explicitModel && VALID_MODELS.includes(explicitModel.toLowerCase())) {
36
+ return explicitModel.toLowerCase();
37
+ }
38
+
39
+ // 2. Frontmatter model
40
+ if (frontmatterModel && VALID_MODELS.includes(frontmatterModel.toLowerCase())) {
41
+ return frontmatterModel.toLowerCase();
42
+ }
43
+
44
+ // 3. Fallback
45
+ return 'haiku';
46
+ }
47
+
48
+ /**
49
+ * Validate a model name.
50
+ *
51
+ * @param {string} model - Model name to validate
52
+ * @returns {boolean} True if valid
53
+ */
54
+ function isValidModel(model) {
55
+ return !!model && VALID_MODELS.includes(model.toLowerCase());
56
+ }
57
+
58
+ /**
59
+ * Estimate cost multiplier for a model relative to haiku baseline.
60
+ *
61
+ * @param {string} model - Model name
62
+ * @param {number} [analyzerCount=5] - Number of analyzers
63
+ * @returns {{ multiplier: number, model: string, perAnalyzerCost: string }}
64
+ */
65
+ function estimateCost(model, analyzerCount) {
66
+ let MODEL_PRICING;
67
+ try {
68
+ MODEL_PRICING = require('./team-events').MODEL_PRICING;
69
+ } catch (_) {
70
+ MODEL_PRICING = {
71
+ haiku: { input: 0.8, output: 4.0 },
72
+ sonnet: { input: 3.0, output: 15.0 },
73
+ opus: { input: 15.0, output: 75.0 },
74
+ };
75
+ }
76
+
77
+ const count = analyzerCount || 5;
78
+ const resolved = resolveModel(model);
79
+ const pricing = MODEL_PRICING[resolved] || MODEL_PRICING.haiku;
80
+ const haikuPricing = MODEL_PRICING.haiku;
81
+
82
+ const multiplier = pricing.output / haikuPricing.output;
83
+ const perAnalyzer = `$${((pricing.input * 50000) / 1_000_000 + (pricing.output * 10000) / 1_000_000).toFixed(3)}`;
84
+
85
+ return {
86
+ multiplier: Math.round(multiplier * 100) / 100,
87
+ model: resolved,
88
+ perAnalyzerCost: perAnalyzer,
89
+ totalEstimate: `~$${(count * ((pricing.input * 50000) / 1_000_000 + (pricing.output * 10000) / 1_000_000)).toFixed(2)}`,
90
+ };
91
+ }
92
+
93
+ module.exports = {
94
+ VALID_MODELS,
95
+ resolveModel,
96
+ isValidModel,
97
+ estimateCost,
98
+ };
@@ -546,7 +546,7 @@ const FEATURE_DETECTORS = {
546
546
  priority: 'medium',
547
547
  trigger: `${coreFiles} source files modified - logic audit available`,
548
548
  action: 'offer',
549
- command: '/agileflow:audit:logic',
549
+ command: '/agileflow:code:logic',
550
550
  phase: 'post-impl',
551
551
  });
552
552
  },