agileflow 2.90.7 → 2.92.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 (144) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +6 -6
  3. package/lib/README.md +178 -0
  4. package/lib/codebase-indexer.js +818 -0
  5. package/lib/colors.js +190 -12
  6. package/lib/consent.js +232 -0
  7. package/lib/correlation.js +277 -0
  8. package/lib/error-codes.js +46 -0
  9. package/lib/errors.js +48 -6
  10. package/lib/file-cache.js +182 -0
  11. package/lib/format-error.js +156 -0
  12. package/lib/path-resolver.js +155 -7
  13. package/lib/paths.js +212 -20
  14. package/lib/placeholder-registry.js +205 -0
  15. package/lib/registry-di.js +358 -0
  16. package/lib/result-schema.js +363 -0
  17. package/lib/result.js +210 -0
  18. package/lib/session-registry.js +13 -0
  19. package/lib/session-state-machine.js +465 -0
  20. package/lib/validate-commands.js +308 -0
  21. package/lib/validate-names.js +3 -3
  22. package/lib/validate.js +116 -52
  23. package/package.json +4 -1
  24. package/scripts/af +34 -0
  25. package/scripts/agent-loop.js +63 -9
  26. package/scripts/agileflow-configure.js +2 -2
  27. package/scripts/agileflow-welcome.js +435 -23
  28. package/scripts/archive-completed-stories.sh +57 -11
  29. package/scripts/claude-tmux.sh +102 -0
  30. package/scripts/damage-control-bash.js +3 -70
  31. package/scripts/damage-control-edit.js +3 -20
  32. package/scripts/damage-control-write.js +3 -20
  33. package/scripts/dependency-check.js +310 -0
  34. package/scripts/get-env.js +11 -4
  35. package/scripts/lib/configure-detect.js +23 -1
  36. package/scripts/lib/configure-features.js +43 -2
  37. package/scripts/lib/context-formatter.js +771 -0
  38. package/scripts/lib/context-loader.js +699 -0
  39. package/scripts/lib/damage-control-utils.js +107 -0
  40. package/scripts/lib/json-utils.sh +162 -0
  41. package/scripts/lib/state-migrator.js +353 -0
  42. package/scripts/lib/story-state-machine.js +437 -0
  43. package/scripts/obtain-context.js +118 -1048
  44. package/scripts/pre-push-check.sh +46 -0
  45. package/scripts/precompact-context.sh +36 -11
  46. package/scripts/query-codebase.js +538 -0
  47. package/scripts/ralph-loop.js +5 -5
  48. package/scripts/session-manager.js +220 -42
  49. package/scripts/spawn-parallel.js +651 -0
  50. package/scripts/tui/blessed/data/watcher.js +180 -0
  51. package/scripts/tui/blessed/index.js +244 -0
  52. package/scripts/tui/blessed/panels/output.js +101 -0
  53. package/scripts/tui/blessed/panels/sessions.js +150 -0
  54. package/scripts/tui/blessed/panels/trace.js +97 -0
  55. package/scripts/tui/blessed/ui/help.js +77 -0
  56. package/scripts/tui/blessed/ui/screen.js +52 -0
  57. package/scripts/tui/blessed/ui/statusbar.js +47 -0
  58. package/scripts/tui/blessed/ui/tabbar.js +99 -0
  59. package/scripts/tui/index.js +38 -30
  60. package/scripts/validators/README.md +143 -0
  61. package/scripts/validators/component-validator.js +239 -0
  62. package/scripts/validators/json-schema-validator.js +186 -0
  63. package/scripts/validators/markdown-validator.js +152 -0
  64. package/scripts/validators/migration-validator.js +129 -0
  65. package/scripts/validators/security-validator.js +380 -0
  66. package/scripts/validators/story-format-validator.js +197 -0
  67. package/scripts/validators/test-result-validator.js +114 -0
  68. package/scripts/validators/workflow-validator.js +247 -0
  69. package/src/core/agents/accessibility.md +6 -0
  70. package/src/core/agents/adr-writer.md +6 -0
  71. package/src/core/agents/analytics.md +6 -0
  72. package/src/core/agents/api.md +6 -0
  73. package/src/core/agents/ci.md +6 -0
  74. package/src/core/agents/codebase-query.md +261 -0
  75. package/src/core/agents/compliance.md +6 -0
  76. package/src/core/agents/configuration-damage-control.md +6 -0
  77. package/src/core/agents/configuration-visual-e2e.md +6 -0
  78. package/src/core/agents/database.md +10 -0
  79. package/src/core/agents/datamigration.md +6 -0
  80. package/src/core/agents/design.md +6 -0
  81. package/src/core/agents/devops.md +6 -0
  82. package/src/core/agents/documentation.md +6 -0
  83. package/src/core/agents/epic-planner.md +6 -0
  84. package/src/core/agents/integrations.md +6 -0
  85. package/src/core/agents/mentor.md +6 -0
  86. package/src/core/agents/mobile.md +6 -0
  87. package/src/core/agents/monitoring.md +6 -0
  88. package/src/core/agents/multi-expert.md +6 -0
  89. package/src/core/agents/performance.md +6 -0
  90. package/src/core/agents/product.md +6 -0
  91. package/src/core/agents/qa.md +6 -0
  92. package/src/core/agents/readme-updater.md +6 -0
  93. package/src/core/agents/refactor.md +6 -0
  94. package/src/core/agents/research.md +6 -0
  95. package/src/core/agents/security.md +6 -0
  96. package/src/core/agents/testing.md +10 -0
  97. package/src/core/agents/ui.md +6 -0
  98. package/src/core/commands/adr.md +114 -0
  99. package/src/core/commands/agent.md +120 -0
  100. package/src/core/commands/assign.md +145 -0
  101. package/src/core/commands/audit.md +401 -0
  102. package/src/core/commands/babysit.md +32 -5
  103. package/src/core/commands/board.md +1 -0
  104. package/src/core/commands/changelog.md +118 -0
  105. package/src/core/commands/configure.md +42 -6
  106. package/src/core/commands/diagnose.md +114 -0
  107. package/src/core/commands/epic.md +205 -1
  108. package/src/core/commands/handoff.md +128 -0
  109. package/src/core/commands/help.md +76 -0
  110. package/src/core/commands/metrics.md +1 -0
  111. package/src/core/commands/pr.md +96 -0
  112. package/src/core/commands/research/analyze.md +1 -0
  113. package/src/core/commands/research/ask.md +2 -0
  114. package/src/core/commands/research/import.md +1 -0
  115. package/src/core/commands/research/list.md +2 -0
  116. package/src/core/commands/research/synthesize.md +584 -0
  117. package/src/core/commands/research/view.md +2 -0
  118. package/src/core/commands/roadmap/analyze.md +400 -0
  119. package/src/core/commands/session/new.md +113 -6
  120. package/src/core/commands/session/spawn.md +197 -0
  121. package/src/core/commands/sprint.md +22 -0
  122. package/src/core/commands/status.md +200 -1
  123. package/src/core/commands/story/list.md +9 -9
  124. package/src/core/commands/story/view.md +1 -0
  125. package/src/core/commands/story.md +143 -4
  126. package/src/core/experts/codebase-query/expertise.yaml +190 -0
  127. package/src/core/experts/codebase-query/question.md +73 -0
  128. package/src/core/experts/codebase-query/self-improve.md +105 -0
  129. package/src/core/templates/agileflow-metadata.json +55 -2
  130. package/src/core/templates/plan-template.md +125 -0
  131. package/src/core/templates/story-lifecycle.md +213 -0
  132. package/src/core/templates/story-template.md +4 -0
  133. package/src/core/templates/tdd-test-template.js +241 -0
  134. package/tools/cli/commands/setup.js +86 -0
  135. package/tools/cli/installers/core/installer.js +94 -0
  136. package/tools/cli/installers/ide/_base-ide.js +20 -11
  137. package/tools/cli/installers/ide/codex.js +29 -47
  138. package/tools/cli/lib/config-manager.js +17 -2
  139. package/tools/cli/lib/content-transformer.js +271 -0
  140. package/tools/cli/lib/error-handler.js +14 -22
  141. package/tools/cli/lib/ide-error-factory.js +421 -0
  142. package/tools/cli/lib/ide-health-monitor.js +364 -0
  143. package/tools/cli/lib/ide-registry.js +114 -1
  144. package/tools/cli/lib/ui.js +14 -25
@@ -0,0 +1,271 @@
1
+ /**
2
+ * content-transformer.js - Reusable content transformation utilities
3
+ *
4
+ * Extracts common content transformation patterns from IDE installers:
5
+ * - replaceReferences: Generic string replacement with pattern support
6
+ * - stripFrontmatter: Remove YAML frontmatter from content
7
+ * - convertFrontmatter: Transform frontmatter keys/values between formats
8
+ * - injectContent: Delegate to existing content-injector
9
+ *
10
+ * Created as part of US-0177: Extract content transformation into reusable helper module
11
+ */
12
+
13
+ const { parseFrontmatter, extractBody } = require('../../../scripts/lib/frontmatter-parser');
14
+
15
+ /**
16
+ * Replace multiple string patterns in content
17
+ *
18
+ * @param {string} content - The content to transform
19
+ * @param {Object|Array} replacements - Either an object of {pattern: replacement} pairs,
20
+ * or an array of {pattern, replacement, flags} objects
21
+ * @returns {string} Content with all replacements applied
22
+ *
23
+ * @example
24
+ * // Object form (simple string replacement)
25
+ * replaceReferences(content, {
26
+ * 'Claude Code': 'Codex CLI',
27
+ * '.claude/': '.codex/',
28
+ * 'CLAUDE.md': 'AGENTS.md'
29
+ * });
30
+ *
31
+ * @example
32
+ * // Array form (with regex flags)
33
+ * replaceReferences(content, [
34
+ * { pattern: 'Claude Code', replacement: 'Codex CLI', flags: 'gi' },
35
+ * { pattern: /\.claude\//g, replacement: '.codex/' }
36
+ * ]);
37
+ */
38
+ function replaceReferences(content, replacements) {
39
+ if (!content || typeof content !== 'string') {
40
+ return content || '';
41
+ }
42
+
43
+ let result = content;
44
+
45
+ if (Array.isArray(replacements)) {
46
+ // Array form: [{pattern, replacement, flags?}]
47
+ for (const item of replacements) {
48
+ if (!item || !item.pattern) continue;
49
+
50
+ let regex;
51
+ if (item.pattern instanceof RegExp) {
52
+ regex = item.pattern;
53
+ } else {
54
+ const flags = item.flags || 'g';
55
+ regex = new RegExp(escapeRegex(item.pattern), flags);
56
+ }
57
+ result = result.replace(regex, item.replacement || '');
58
+ }
59
+ } else if (typeof replacements === 'object' && replacements !== null) {
60
+ // Object form: {pattern: replacement}
61
+ for (const [pattern, replacement] of Object.entries(replacements)) {
62
+ result = result.replace(new RegExp(escapeRegex(pattern), 'g'), replacement);
63
+ }
64
+ }
65
+
66
+ return result;
67
+ }
68
+
69
+ /**
70
+ * Escape special regex characters in a string
71
+ * @param {string} str - String to escape
72
+ * @returns {string} Escaped string safe for use in RegExp
73
+ */
74
+ function escapeRegex(str) {
75
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
76
+ }
77
+
78
+ /**
79
+ * Remove YAML frontmatter from content, returning only the body
80
+ *
81
+ * @param {string} content - Content with optional YAML frontmatter
82
+ * @returns {string} Content body without frontmatter
83
+ *
84
+ * @example
85
+ * const body = stripFrontmatter(`---
86
+ * title: My Document
87
+ * ---
88
+ *
89
+ * # Heading
90
+ * Content here`);
91
+ * // Returns: "# Heading\nContent here"
92
+ */
93
+ function stripFrontmatter(content) {
94
+ return extractBody(content);
95
+ }
96
+
97
+ /**
98
+ * Convert frontmatter between formats using a mapping configuration
99
+ *
100
+ * @param {Object} frontmatter - Parsed frontmatter object
101
+ * @param {Object} config - Conversion configuration
102
+ * @param {Object} [config.keyMap] - Map of source keys to target keys
103
+ * @param {Object} [config.valueMap] - Map of key names to value transformation functions
104
+ * @param {Array} [config.include] - Only include these keys (whitelist)
105
+ * @param {Array} [config.exclude] - Exclude these keys (blacklist)
106
+ * @param {Object} [config.defaults] - Default values to add if not present
107
+ * @returns {Object} Transformed frontmatter object
108
+ *
109
+ * @example
110
+ * const converted = convertFrontmatter(
111
+ * { name: 'security', description: 'Security agent', tools: ['Read', 'Write'] },
112
+ * {
113
+ * keyMap: { name: 'skill_name', tools: 'allowed_tools' },
114
+ * valueMap: { description: (v) => v.replace('agent', 'skill') },
115
+ * exclude: ['internal_only'],
116
+ * defaults: { version: '1.0' }
117
+ * }
118
+ * );
119
+ */
120
+ function convertFrontmatter(frontmatter, config = {}) {
121
+ if (!frontmatter || typeof frontmatter !== 'object') {
122
+ return {};
123
+ }
124
+
125
+ const { keyMap = {}, valueMap = {}, include, exclude = [], defaults = {} } = config;
126
+
127
+ const result = { ...defaults };
128
+
129
+ for (const [key, value] of Object.entries(frontmatter)) {
130
+ // Skip excluded keys
131
+ if (exclude.includes(key)) continue;
132
+
133
+ // Skip if not in include list (when include is specified)
134
+ if (include && !include.includes(key)) continue;
135
+
136
+ // Map key name if mapping exists
137
+ const targetKey = keyMap[key] || key;
138
+
139
+ // Transform value if transformation exists
140
+ const targetValue = valueMap[key] ? valueMap[key](value) : value;
141
+
142
+ result[targetKey] = targetValue;
143
+ }
144
+
145
+ return result;
146
+ }
147
+
148
+ /**
149
+ * Inject dynamic content into a template using content-injector
150
+ *
151
+ * @param {string} content - Content with placeholders
152
+ * @param {Object} options - Injection options
153
+ * @param {string} options.coreDir - Path to AgileFlow core directory
154
+ * @param {string} [options.agileflowFolder] - Target AgileFlow folder name (default: '.agileflow')
155
+ * @param {string} [options.version] - Version string to inject
156
+ * @returns {string} Content with placeholders replaced
157
+ */
158
+ function injectContent(content, options) {
159
+ const { injectContent: inject } = require('./content-injector');
160
+ return inject(content, options);
161
+ }
162
+
163
+ /**
164
+ * Parse frontmatter from content
165
+ * Re-exported from frontmatter-parser for convenience
166
+ *
167
+ * @param {string} content - Content with YAML frontmatter
168
+ * @returns {Object} Parsed frontmatter as object
169
+ */
170
+ function getFrontmatter(content) {
171
+ return parseFrontmatter(content);
172
+ }
173
+
174
+ /**
175
+ * Common replacement patterns for IDE conversions
176
+ */
177
+ const IDE_REPLACEMENTS = {
178
+ /**
179
+ * Claude Code to Codex CLI conversions
180
+ */
181
+ codex: {
182
+ 'Claude Code': 'Codex CLI',
183
+ 'claude code': 'Codex CLI',
184
+ CLAUDE_CODE: 'CODEX_CLI',
185
+ 'CLAUDE.md': 'AGENTS.md',
186
+ '.claude/': '.codex/',
187
+ '.claude\\': '.codex\\',
188
+ 'Task tool': 'skill invocation',
189
+ 'Task agent': 'skill invocation',
190
+ },
191
+
192
+ /**
193
+ * Claude Code to Cursor conversions
194
+ */
195
+ cursor: {
196
+ 'Claude Code': 'Cursor',
197
+ 'claude code': 'Cursor',
198
+ '.claude/': '.cursor/',
199
+ '.claude\\': '.cursor\\',
200
+ },
201
+
202
+ /**
203
+ * Claude Code to Windsurf conversions
204
+ */
205
+ windsurf: {
206
+ 'Claude Code': 'Windsurf',
207
+ 'claude code': 'Windsurf',
208
+ '.claude/': '.windsurf/',
209
+ '.claude\\': '.windsurf\\',
210
+ },
211
+ };
212
+
213
+ /**
214
+ * Create docs folder reference replacements
215
+ *
216
+ * @param {string} targetFolder - Target docs folder name (e.g., 'project-docs')
217
+ * @returns {Object} Replacement patterns for docs references
218
+ */
219
+ function createDocsReplacements(targetFolder) {
220
+ if (targetFolder === 'docs') {
221
+ return {}; // No changes needed
222
+ }
223
+
224
+ return {
225
+ 'docs/': `${targetFolder}/`,
226
+ '`docs/': `\`${targetFolder}/`,
227
+ '"docs/': `"${targetFolder}/`,
228
+ "'docs/": `'${targetFolder}/`,
229
+ '(docs/': `(${targetFolder}/`,
230
+ '[docs/': `[${targetFolder}/`,
231
+ };
232
+ }
233
+
234
+ /**
235
+ * Transform content for a specific IDE target
236
+ *
237
+ * @param {string} content - Source content
238
+ * @param {string} targetIde - Target IDE: 'codex', 'cursor', 'windsurf'
239
+ * @param {Object} [options] - Additional options
240
+ * @param {string} [options.docsFolder] - Custom docs folder name
241
+ * @param {Object} [options.additionalReplacements] - Extra replacements to apply
242
+ * @returns {string} Transformed content
243
+ */
244
+ function transformForIde(content, targetIde, options = {}) {
245
+ const { docsFolder, additionalReplacements = {} } = options;
246
+
247
+ // Start with IDE-specific replacements
248
+ const replacements = { ...(IDE_REPLACEMENTS[targetIde] || {}) };
249
+
250
+ // Add docs folder replacements if needed
251
+ if (docsFolder && docsFolder !== 'docs') {
252
+ Object.assign(replacements, createDocsReplacements(docsFolder));
253
+ }
254
+
255
+ // Add any additional custom replacements
256
+ Object.assign(replacements, additionalReplacements);
257
+
258
+ return replaceReferences(content, replacements);
259
+ }
260
+
261
+ module.exports = {
262
+ replaceReferences,
263
+ stripFrontmatter,
264
+ convertFrontmatter,
265
+ injectContent,
266
+ getFrontmatter,
267
+ escapeRegex,
268
+ IDE_REPLACEMENTS,
269
+ createDocsReplacements,
270
+ transformForIde,
271
+ };
@@ -7,9 +7,15 @@
7
7
  * - CRITICAL: Severe errors (exit 1 + stack trace if DEBUG=1)
8
8
  *
9
9
  * Error output format: "X <problem> | Action: <what to do> | Run: <command>"
10
+ *
11
+ * Note: Formatting logic is extracted to lib/format-error.js for standalone use.
10
12
  */
11
13
 
12
- const { c } = require('../../../lib/colors');
14
+ const {
15
+ formatError: formatErrorHelper,
16
+ formatWarning: formatWarningHelper,
17
+ formatErrorWithStack,
18
+ } = require('../../../lib/format-error');
13
19
 
14
20
  class ErrorHandler {
15
21
  /**
@@ -30,14 +36,7 @@ class ErrorHandler {
30
36
  * @returns {string} Formatted error string
31
37
  */
32
38
  formatError(message, actionText, commandHint) {
33
- let output = `${c.red}\u2716${c.reset} ${message}`;
34
- if (actionText) {
35
- output += ` ${c.dim}|${c.reset} ${c.cyan}Action:${c.reset} ${actionText}`;
36
- }
37
- if (commandHint) {
38
- output += ` ${c.dim}|${c.reset} ${c.green}Run:${c.reset} ${c.bold}${commandHint}${c.reset}`;
39
- }
40
- return output;
39
+ return formatErrorHelper(message, actionText, commandHint);
41
40
  }
42
41
 
43
42
  /**
@@ -48,14 +47,7 @@ class ErrorHandler {
48
47
  * @returns {string} Formatted warning string
49
48
  */
50
49
  formatWarning(message, actionText, commandHint) {
51
- let output = `${c.yellow}\u26A0${c.reset} ${message}`;
52
- if (actionText) {
53
- output += ` ${c.dim}|${c.reset} ${c.cyan}Action:${c.reset} ${actionText}`;
54
- }
55
- if (commandHint) {
56
- output += ` ${c.dim}|${c.reset} ${c.green}Run:${c.reset} ${c.bold}${commandHint}${c.reset}`;
57
- }
58
- return output;
50
+ return formatWarningHelper(message, actionText, commandHint);
59
51
  }
60
52
 
61
53
  /**
@@ -94,11 +86,11 @@ class ErrorHandler {
94
86
  * @param {Error} [error] - Original error object for stack trace
95
87
  */
96
88
  critical(message, actionText, commandHint, error) {
97
- console.error(this.formatError(message, actionText, commandHint));
98
- if (process.env.DEBUG === '1' && error?.stack) {
99
- console.error(`\n${c.dim}Stack trace:${c.reset}`);
100
- console.error(c.dim + error.stack + c.reset);
101
- }
89
+ const formatted = formatErrorWithStack(message, error, {
90
+ action: actionText,
91
+ command: commandHint,
92
+ });
93
+ console.error(formatted);
102
94
  process.exit(1);
103
95
  }
104
96