fraim-framework 2.0.49 → 2.0.52

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.
@@ -0,0 +1,116 @@
1
+ # Phase: Retrospective
2
+
3
+ ## INTENT
4
+ To conduct a comprehensive retrospective of the completed work while full context is available, capturing learnings and insights before branch cleanup and resolution. This phase applies to all workflow types (spec, design, implement, test).
5
+
6
+ ## TRIGGER
7
+ This phase is triggered after PR approval (`wait-for-pr-review` completion) and before `resolve` phase for all workflow types.
8
+
9
+ ## CONTEXT ADVANTAGES
10
+ - **Full Work Context**: All changes, decisions, and challenges are fresh in memory
11
+ - **Branch Available**: Can reference specific commits, diffs, and work artifacts
12
+ - **Problem-Solution Mapping**: Clear connection between original problem and completed solution
13
+ - **Fresh Insights**: Recent experience provides accurate reflection on what worked/didn't work
14
+ - **PR Feedback Available**: Can analyze and learn from user feedback received during review
15
+ - **Complete Journey**: Can analyze entire workflow from start to finish
16
+
17
+ ## WORKFLOW
18
+
19
+ ### Step 1: Retrospective Preparation
20
+ - Ensure PR is approved and ready for merge
21
+ - Gather work artifacts (commits, documents, test results, etc.)
22
+ - Review original issue requirements and acceptance criteria
23
+ - **Collect PR feedback**: Review all comments, suggestions, and feedback received during PR review
24
+ - Analyze user feedback patterns and themes
25
+ - Identify key decision points and challenges encountered
26
+
27
+ ### Step 2: Create Retrospective Document
28
+ - Create (or use existing) retrospective file: `retrospectives/issue-{issue-number}-{kebab-title}-postmortem.md`
29
+ - Use retrospective template: `get_fraim_file({ path: "templates/retrospective/RETROSPECTIVE-TEMPLATE.md" })`
30
+ - Document while work context is fresh and complete
31
+
32
+ ### Step 3: Work Analysis
33
+ - **What Went Well**: Successful approaches, tools, and techniques used
34
+ - **What Went Poorly**: Challenges, obstacles, and inefficiencies encountered
35
+ - **Root Cause Analysis**: Why problems occurred, not just what happened
36
+ - **Decision Analysis**: Review key decisions made during the work
37
+ - **PR Feedback Analysis**: What user feedback revealed about the work quality
38
+ - **Process Effectiveness**: How well the workflow supported the work
39
+
40
+ ### Step 4: Learning Extraction
41
+ - **Key Learnings**: Specific insights that can help future work of this type
42
+ - **Process Improvements**: Workflow or rule changes that would help
43
+ - **Tool/Technique Discoveries**: New approaches or tools that proved valuable
44
+ - **Anti-Patterns Identified**: Approaches to avoid in future work
45
+ - **User Feedback Patterns**: Common themes in user feedback to address
46
+ - **Quality Insights**: What contributed to or detracted from work quality
47
+
48
+ ### Step 5: Prevention Measures
49
+ - **Specific Actions**: Concrete steps to prevent similar issues in future work
50
+ - **Rule Updates**: Suggestions for updating FRAIM rules or workflows
51
+ - **Knowledge Sharing**: Insights that should be shared with other agents
52
+ - **Process Enhancements**: Workflow improvements based on experience
53
+ - **Feedback Integration**: How to better incorporate user feedback in future work
54
+ - **Quality Improvements**: Changes to improve work quality
55
+
56
+ ### Step 6: Validation and Completion
57
+ - Ensure retrospective meets quality criteria
58
+ - Validate all template sections are complete
59
+ - Confirm learnings are actionable and specific
60
+ - Verify PR feedback has been analyzed and learned from
61
+ - Check that prevention measures are concrete and implementable
62
+ - Mark phase complete and proceed to resolve
63
+
64
+ ## VALIDATION CRITERIA
65
+ - ✅ Retrospective document created using template
66
+ - ✅ Root cause analysis completed (not just symptoms)
67
+ - ✅ Prevention measures documented and actionable
68
+ - ✅ Key learnings extracted and documented
69
+ - ✅ Process improvements identified
70
+ - ✅ PR feedback analyzed and lessons captured
71
+ - ✅ All template sections completed with substantial content
72
+ - ✅ Retrospective quality meets standards
73
+ - ✅ Learnings are specific to the workflow type and transferable
74
+
75
+ ## PHASE COMPLETION
76
+ This phase is complete when:
77
+ 1. Comprehensive retrospective document is created
78
+ 2. All validation criteria are met
79
+ 3. Learnings are documented for future reference
80
+ 4. PR feedback has been systematically analyzed
81
+ 5. Prevention measures are specific and actionable
82
+ 6. Process improvements are identified
83
+ 7. Agent is ready to proceed to resolve phase
84
+
85
+ ## WORKFLOW-SPECIFIC FOCUS AREAS
86
+
87
+ ### Spec Retrospective Focus
88
+ - Requirements gathering effectiveness
89
+ - Stakeholder engagement quality
90
+ - Competitive analysis thoroughness
91
+ - User experience definition clarity
92
+ - Validation plan completeness
93
+
94
+ ### Design Retrospective Focus
95
+ - Technical decision quality
96
+ - Architecture choice rationale
97
+ - Design review feedback incorporation
98
+ - Technical feasibility assessment
99
+ - Implementation guidance clarity
100
+
101
+ ### Implement Retrospective Focus
102
+ - Code quality and maintainability
103
+ - Technical approach effectiveness
104
+ - Testing strategy success
105
+ - Performance considerations
106
+ - Integration challenges
107
+
108
+ ### Test Retrospective Focus
109
+ - Test coverage adequacy
110
+ - Quality assurance approach effectiveness
111
+ - Testing strategy validation
112
+ - Bug detection capability
113
+ - Test maintenance considerations
114
+
115
+ ## NEXT PHASE
116
+ After completing retrospective, proceed to `resolve` phase for final merge and cleanup.
@@ -0,0 +1,105 @@
1
+ # Phase: spec-competitor-analysis
2
+
3
+ ## INTENT
4
+ To conduct systematic competitive research and analysis for the feature being specified, ensuring comprehensive understanding of competitive landscape and clear differentiation strategy.
5
+
6
+ ## OUTCOME
7
+ A comprehensive competitive analysis that:
8
+ - Documents all configured competitors and their approaches
9
+ - Identifies new competitors through systematic research
10
+ - Proposes configuration updates with user approval
11
+ - Defines clear differentiation strategy and competitive positioning
12
+ - Updates the specification with complete competitive landscape analysis
13
+
14
+ ## TRIGGER
15
+ This phase is triggered after `spec-spec` completion and before `spec-completeness-review`.
16
+
17
+ ## CONTEXT ADVANTAGES
18
+ - **Full Feature Context**: Complete understanding of proposed feature and requirements
19
+ - **Fresh Research**: Current competitive landscape information
20
+ - **Strategic Positioning**: Ability to influence feature design based on competitive insights
21
+ - **Configuration-Driven**: Systematic analysis of known competitors plus discovery of new ones
22
+
23
+ ## WORKFLOW
24
+
25
+ ### Step 1: Load Competitor Configuration
26
+ - Read `.fraim/config.json` competitors section
27
+ - Extract configured competitors and their competitive spaces
28
+ - Note any existing competitive intelligence
29
+
30
+ ### Step 2: Research Configured Competitors
31
+ For each competitor in config:
32
+ - Research their current solution for this feature area
33
+ - Analyze their strengths and weaknesses in this space
34
+ - Gather customer feedback and reviews
35
+ - Assess market position and pricing approach
36
+ - Document findings in structured format
37
+
38
+ ### Step 3: Discover Additional Competitors
39
+ - Use web search to find other competitors in the feature space
40
+ - Research market for competitors not in configuration
41
+ - Identify direct, adjacent, and emerging competitors
42
+ - Focus on competitors specifically relevant to this feature
43
+
44
+ ### Step 4: Competitor Configuration Updates
45
+ - **Identify New Competitors**: Present newly discovered competitors to user
46
+ - **Configuration Proposal**: Suggest adding relevant competitors to `.fraim/config.json`
47
+ - **User Approval**: Ask user to approve additions: "Found new competitor 'X' in space 'Y'. Add to config?"
48
+ - **Auto-Update**: If user approves, automatically update configuration file
49
+ - **Documentation**: Note configuration changes in competitive analysis
50
+
51
+ ### Step 5: Competitive Analysis
52
+ - Compare competitor approaches to our proposed solution
53
+ - Identify competitive advantages and disadvantages
54
+ - Develop differentiation strategy
55
+ - Plan competitive response strategies
56
+ - Define market positioning approach
57
+
58
+ ### Step 6: Update Specification
59
+ - Update Competitive Landscape section with findings
60
+ - Ensure all configured competitors are covered
61
+ - Include newly discovered competitors
62
+ - Add competitive positioning strategy
63
+ - Document research sources and methodology
64
+ - Validate analysis completeness
65
+
66
+ ## VALIDATION
67
+
68
+ ### Phase Complete When:
69
+ - ✅ All configured competitors analyzed
70
+ - ✅ Additional competitors discovered through research
71
+ - ✅ User consulted on adding new competitors to config
72
+ - ✅ Configuration updated with user-approved competitors
73
+ - ✅ Competitive positioning strategy defined
74
+ - ✅ Differentiation advantages clearly articulated
75
+ - ✅ Research sources documented
76
+ - ✅ Analysis covers both configured and discovered competitors
77
+ - ✅ Specification competitive landscape section updated
78
+
79
+ ### Report Back:
80
+ When this phase is complete, call:
81
+ ```javascript
82
+ seekCoachingOnNextStep({
83
+ workflowType: "spec",
84
+ issueNumber: "your-issue-number",
85
+ currentPhase: "spec-competitor-analysis",
86
+ status: "complete",
87
+ evidence: {
88
+ competitorsAnalyzed: ["competitor1", "competitor2"],
89
+ newCompetitorsFound: ["new-competitor1"],
90
+ configurationUpdated: true,
91
+ differentiationStrategy: "summary of strategy",
92
+ specificationUpdated: true
93
+ }
94
+ })
95
+ ```
96
+
97
+ ### Phase Incomplete If:
98
+ - Configuration competitors not fully researched
99
+ - No additional competitor discovery attempted
100
+ - User not consulted on configuration updates
101
+ - Competitive positioning strategy missing
102
+ - Specification not updated with findings
103
+
104
+ ## NEXT PHASE
105
+ After completing competitor-analysis, proceed to `spec-completeness-review` phase.
@@ -155,8 +155,11 @@ ${this.getValidPhasesForIssueType(issueType).join(' → ')}
155
155
  * Generate completion message for completed phases
156
156
  */
157
157
  async generateCompletionMessage(args) {
158
- // Handle workflow completion for wait-for-pr-review phase when PR is approved
159
- if (args.currentPhase === 'wait-for-pr-review') {
158
+ // Determine next phase and provide its instructions
159
+ const issueType = this.extractIssueType(args.findings, args.evidence);
160
+ const nextPhase = (0, phase_flow_js_1.getNextPhase)(args.currentPhase, args.workflowType, issueType);
161
+ if (!nextPhase) {
162
+ // This is the final phase - show completion message
160
163
  return `# 🎉 ${args.workflowType.charAt(0).toUpperCase() + args.workflowType.slice(1)} Complete!
161
164
 
162
165
  **Congratulations!** You have successfully completed all ${args.workflowType} phases for issue #${args.issueNumber}.
@@ -165,30 +168,11 @@ ${this.getValidPhasesForIssueType(issueType).join(' → ')}
165
168
  ${this.getAccomplishmentsForWorkflow(args.workflowType)}
166
169
 
167
170
  ## 📋 Final Evidence Summary
168
- ${JSON.stringify(args.evidence || {}, null, 2)}
171
+ ${JSON.stringify(args.evidence || args.findings || {}, null, 2)}
169
172
 
170
173
  `;
171
174
  }
172
175
  else {
173
- // Determine next phase and provide its instructions
174
- const issueType = this.extractIssueType(args.findings, args.evidence);
175
- const nextPhase = (0, phase_flow_js_1.getNextPhase)(args.currentPhase, args.workflowType, issueType);
176
- if (!nextPhase) {
177
- return `# 🎉 Phase Complete!
178
-
179
- **Phase:** ${args.currentPhase}
180
- **Status:** Complete
181
-
182
- Great work! You've completed the ${args.currentPhase} phase.
183
-
184
- ## Evidence Summary
185
- ${JSON.stringify(args.evidence || args.findings || {}, null, 2)}
186
-
187
- ## 🚨 Error: No Next Phase Found
188
- Unable to determine the next phase. This might indicate an issue with the phase flow logic.
189
- Please check your workflow type and current phase.
190
- `;
191
- }
192
176
  // Get instructions for the next phase
193
177
  const nextPhaseInstructions = await this.getPhaseInstructions(nextPhase, args.workflowType);
194
178
  return `# 🎉 Phase Complete!
@@ -351,9 +335,20 @@ Remember: Take your time and follow each step carefully. The phase guidance cont
351
335
  */
352
336
  async getPhaseInstructions(phase, workflowType) {
353
337
  try {
354
- // Read phase instructions from .md files based on workflow type
338
+ // Special handling for shared phases
339
+ const sharedPhases = ['retrospective', 'submit-pr', 'wait-for-pr-review', 'address-pr-feedback'];
355
340
  let phasePath;
356
- if (workflowType === 'implement') {
341
+ if (sharedPhases.includes(phase)) {
342
+ // Check if it's in root ai-manager-rules directory (like retrospective)
343
+ if (phase === 'retrospective') {
344
+ phasePath = `ai-manager-rules/${phase}.md`;
345
+ }
346
+ else {
347
+ // Other shared phases are in shared-phases subdirectory
348
+ phasePath = `ai-manager-rules/shared-phases/${phase}.md`;
349
+ }
350
+ }
351
+ else if (workflowType === 'implement') {
357
352
  phasePath = `ai-manager-rules/implement-phases/${phase}.md`;
358
353
  }
359
354
  else {
@@ -364,26 +359,35 @@ Remember: Take your time and follow each step carefully. The phase guidance cont
364
359
  if (phaseFile && (0, fs_1.existsSync)(phaseFile.fullPath)) {
365
360
  return (0, fs_1.readFileSync)(phaseFile.fullPath, 'utf8');
366
361
  }
367
- // If not found in workflow-specific directory, try shared-phases
368
- const sharedPhasePath = `ai-manager-rules/shared-phases/${phase}.md`;
369
- phaseFile = this.fileIndex.get(sharedPhasePath);
370
- if (phaseFile && (0, fs_1.existsSync)(phaseFile.fullPath)) {
371
- return (0, fs_1.readFileSync)(phaseFile.fullPath, 'utf8');
362
+ // If not found and not a shared phase, try shared-phases directory
363
+ if (!sharedPhases.includes(phase)) {
364
+ const sharedPhasePath = `ai-manager-rules/shared-phases/${phase}.md`;
365
+ phaseFile = this.fileIndex.get(sharedPhasePath);
366
+ if (phaseFile && (0, fs_1.existsSync)(phaseFile.fullPath)) {
367
+ return (0, fs_1.readFileSync)(phaseFile.fullPath, 'utf8');
368
+ }
372
369
  }
373
370
  // Fallback: try to read directly from filesystem
374
371
  const { join } = require('path');
375
- const possiblePaths = [
376
- // Try workflow-specific paths first
377
- join(process.cwd(), 'dist', 'registry', phasePath),
378
- join(process.cwd(), 'registry', phasePath),
379
- join(__dirname, '..', '..', 'registry', phasePath),
380
- join(__dirname, '..', 'registry', phasePath),
381
- // Try shared-phases paths
382
- join(process.cwd(), 'dist', 'registry', sharedPhasePath),
383
- join(process.cwd(), 'registry', sharedPhasePath),
384
- join(__dirname, '..', '..', 'registry', sharedPhasePath),
385
- join(__dirname, '..', 'registry', sharedPhasePath)
386
- ];
372
+ const possiblePaths = [];
373
+ if (sharedPhases.includes(phase)) {
374
+ if (phase === 'retrospective') {
375
+ // Retrospective is in root ai-manager-rules directory
376
+ possiblePaths.push(join(process.cwd(), 'dist', 'registry', `ai-manager-rules/${phase}.md`), join(process.cwd(), 'registry', `ai-manager-rules/${phase}.md`), join(__dirname, '..', '..', 'registry', `ai-manager-rules/${phase}.md`), join(__dirname, '..', 'registry', `ai-manager-rules/${phase}.md`));
377
+ }
378
+ else {
379
+ // Other shared phases are in shared-phases subdirectory
380
+ const sharedPhasePath = `ai-manager-rules/shared-phases/${phase}.md`;
381
+ possiblePaths.push(join(process.cwd(), 'dist', 'registry', sharedPhasePath), join(process.cwd(), 'registry', sharedPhasePath), join(__dirname, '..', '..', 'registry', sharedPhasePath), join(__dirname, '..', 'registry', sharedPhasePath));
382
+ }
383
+ }
384
+ else {
385
+ // For workflow-specific phases
386
+ possiblePaths.push(join(process.cwd(), 'dist', 'registry', phasePath), join(process.cwd(), 'registry', phasePath), join(__dirname, '..', '..', 'registry', phasePath), join(__dirname, '..', 'registry', phasePath));
387
+ // Also try shared-phases directory
388
+ const sharedPhasePath = `ai-manager-rules/shared-phases/${phase}.md`;
389
+ possiblePaths.push(join(process.cwd(), 'dist', 'registry', sharedPhasePath), join(process.cwd(), 'registry', sharedPhasePath), join(__dirname, '..', '..', 'registry', sharedPhasePath), join(__dirname, '..', 'registry', sharedPhasePath));
390
+ }
387
391
  for (const fullPath of possiblePaths) {
388
392
  if ((0, fs_1.existsSync)(fullPath)) {
389
393
  console.log(`📖 AI Coach: Reading phase file from ${fullPath}`);
@@ -392,7 +396,7 @@ Remember: Take your time and follow each step carefully. The phase guidance cont
392
396
  }
393
397
  return `# Phase: ${phase}
394
398
 
395
- **Error**: Phase instructions not found at ${phasePath} or ${sharedPhasePath}
399
+ **Error**: Phase instructions not found
396
400
 
397
401
  Tried paths:
398
402
  ${possiblePaths.map(p => `- ${p}`).join('\n')}
@@ -23,6 +23,7 @@ const BUG_PHASE_FLOW = [
23
23
  'implement-completeness-review',
24
24
  'submit-pr',
25
25
  'wait-for-pr-review',
26
+ 'retrospective',
26
27
  ];
27
28
  const FEATURE_PHASE_FLOW = [
28
29
  'implement-scoping',
@@ -34,24 +35,29 @@ const FEATURE_PHASE_FLOW = [
34
35
  'implement-completeness-review',
35
36
  'submit-pr',
36
37
  'wait-for-pr-review',
38
+ 'retrospective',
37
39
  ];
38
40
  const SPEC_PHASE_FLOW = [
39
41
  'spec-spec',
42
+ 'spec-competitor-analysis',
40
43
  'spec-completeness-review',
41
44
  'submit-pr',
42
45
  'wait-for-pr-review',
46
+ 'retrospective',
43
47
  ];
44
48
  const DESIGN_PHASE_FLOW = [
45
49
  'design-design',
46
50
  'design-completeness-review',
47
51
  'submit-pr',
48
52
  'wait-for-pr-review',
53
+ 'retrospective',
49
54
  ];
50
55
  const TEST_PHASE_FLOW = [
51
56
  'test-test',
52
57
  'test-validate',
53
58
  'submit-pr',
54
59
  'wait-for-pr-review',
60
+ 'retrospective',
55
61
  ];
56
62
  /**
57
63
  * Get the next phase in the workflow
@@ -169,6 +175,9 @@ function getPhaseOnFailure(failedPhase, workflowType, issueType // eslint-disabl
169
175
  case 'wait-for-pr-review':
170
176
  // PR feedback should go to address-pr-feedback phase
171
177
  return 'address-pr-feedback';
178
+ case 'retrospective':
179
+ // If retrospective fails, retry the same phase
180
+ return 'retrospective';
172
181
  case 'address-pr-feedback':
173
182
  // If addressing PR feedback fails, retry the same phase
174
183
  return 'address-pr-feedback';
@@ -181,12 +190,16 @@ function getPhaseOnFailure(failedPhase, workflowType, issueType // eslint-disabl
181
190
  switch (failedPhase) {
182
191
  case 'spec-spec':
183
192
  return 'spec-spec'; // Start over at spec
193
+ case 'spec-competitor-analysis':
194
+ return 'spec-spec'; // Go back to improve spec if competitive analysis fails
184
195
  case 'spec-completeness-review':
185
- return 'spec-spec'; // Go back to improve spec
196
+ return 'spec-spec'; // Go back to improve competitive analysis
186
197
  case 'submit-pr':
187
198
  return 'spec-completeness-review';
188
199
  case 'wait-for-pr-review':
189
200
  return 'address-pr-feedback'; // PR feedback goes to address phase
201
+ case 'retrospective':
202
+ return 'retrospective'; // Retry retrospective if it fails
190
203
  case 'address-pr-feedback':
191
204
  return 'address-pr-feedback'; // Retry addressing feedback
192
205
  default:
@@ -204,6 +217,8 @@ function getPhaseOnFailure(failedPhase, workflowType, issueType // eslint-disabl
204
217
  return 'design-completeness-review';
205
218
  case 'wait-for-pr-review':
206
219
  return 'address-pr-feedback'; // PR feedback goes to address phase
220
+ case 'retrospective':
221
+ return 'retrospective'; // Retry retrospective if it fails
207
222
  case 'address-pr-feedback':
208
223
  return 'address-pr-feedback'; // Retry addressing feedback
209
224
  default:
@@ -221,6 +236,8 @@ function getPhaseOnFailure(failedPhase, workflowType, issueType // eslint-disabl
221
236
  return 'test-validate';
222
237
  case 'wait-for-pr-review':
223
238
  return 'address-pr-feedback'; // PR feedback goes to address phase
239
+ case 'retrospective':
240
+ return 'retrospective'; // Retry retrospective if it fails
224
241
  case 'address-pr-feedback':
225
242
  return 'address-pr-feedback'; // Retry addressing feedback
226
243
  default:
@@ -20,8 +20,15 @@ const runSync = async (options) => {
20
20
  const workflowsRelativePath = config.customizations?.workflowsPath || '.fraim/workflows';
21
21
  const workflowsDir = path_1.default.resolve(projectRoot, workflowsRelativePath);
22
22
  const digestPath = path_1.default.join(fraimDir, '.digest');
23
- // Check for CLI updates first
24
- await checkAndUpdateCLI();
23
+ // Check for CLI updates first (but skip during installation to prevent loops)
24
+ const isPostInstall = process.env.npm_lifecycle_event === 'postinstall' ||
25
+ process.env.npm_lifecycle_script === 'postinstall';
26
+ if (!options.skipUpdates && !isPostInstall) {
27
+ await checkAndUpdateCLI();
28
+ }
29
+ else if (isPostInstall) {
30
+ console.log(chalk_1.default.gray('⏭️ Skipping auto-update check during installation to prevent loops.'));
31
+ }
25
32
  // In npm package, stubs are in node_modules/@fraim/framework/registry/stubs/workflows
26
33
  // We need to handle both "running from source" (src/cli/commands) and "running from dist" (dist/src/cli/commands)
27
34
  // Try 4 levels up (dist/src/cli/commands -> root)
@@ -168,6 +175,14 @@ const runSync = async (options) => {
168
175
  exports.runSync = runSync;
169
176
  async function checkAndUpdateCLI() {
170
177
  try {
178
+ // Additional safety: check if we're in a global npm install context
179
+ const isGlobalInstall = process.env.npm_config_global === 'true' ||
180
+ process.env.npm_config_prefix ||
181
+ process.cwd().includes('node_modules');
182
+ if (isGlobalInstall) {
183
+ console.log(chalk_1.default.gray('⏭️ Skipping auto-update during global installation.'));
184
+ return;
185
+ }
171
186
  console.log(chalk_1.default.blue('🔍 Checking for FRAIM CLI updates...'));
172
187
  const currentVersion = (0, version_utils_1.getFraimVersion)();
173
188
  const latestVersion = await getLatestNpmVersionHttp('fraim-framework');
@@ -270,4 +285,5 @@ async function updateGlobalPackageHttp(packageName, version) {
270
285
  exports.syncCommand = new commander_1.Command('sync')
271
286
  .description('Sync workflow stubs from the framework registry')
272
287
  .option('-f, --force', 'Force sync even if digest matches')
288
+ .option('--skip-updates', 'Skip checking for CLI updates')
273
289
  .action(exports.runSync);
@@ -289,11 +289,16 @@ const phase_flow_js_1 = require("../src/ai-manager/phase-flow.js");
289
289
  }
290
290
  });
291
291
  (0, node_test_1.it)('should handle boundary conditions in phase flows', () => {
292
- // Test last phase in each workflow
293
- node_assert_1.default.strictEqual((0, phase_flow_js_1.getNextPhase)('wait-for-pr-review', 'spec'), null);
294
- node_assert_1.default.strictEqual((0, phase_flow_js_1.getNextPhase)('wait-for-pr-review', 'design'), null);
295
- node_assert_1.default.strictEqual((0, phase_flow_js_1.getNextPhase)('wait-for-pr-review', 'implement', 'bug'), null);
296
- node_assert_1.default.strictEqual((0, phase_flow_js_1.getNextPhase)('wait-for-pr-review', 'implement', 'feature'), null);
292
+ // Test last phase in each workflow - retrospective is now the final phase
293
+ node_assert_1.default.strictEqual((0, phase_flow_js_1.getNextPhase)('retrospective', 'spec'), null);
294
+ node_assert_1.default.strictEqual((0, phase_flow_js_1.getNextPhase)('retrospective', 'design'), null);
295
+ node_assert_1.default.strictEqual((0, phase_flow_js_1.getNextPhase)('retrospective', 'implement', 'bug'), null);
296
+ node_assert_1.default.strictEqual((0, phase_flow_js_1.getNextPhase)('retrospective', 'implement', 'feature'), null);
297
+ // Test that wait-for-pr-review transitions to retrospective
298
+ node_assert_1.default.strictEqual((0, phase_flow_js_1.getNextPhase)('wait-for-pr-review', 'spec'), 'retrospective');
299
+ node_assert_1.default.strictEqual((0, phase_flow_js_1.getNextPhase)('wait-for-pr-review', 'design'), 'retrospective');
300
+ node_assert_1.default.strictEqual((0, phase_flow_js_1.getNextPhase)('wait-for-pr-review', 'implement', 'bug'), 'retrospective');
301
+ node_assert_1.default.strictEqual((0, phase_flow_js_1.getNextPhase)('wait-for-pr-review', 'implement', 'feature'), 'retrospective');
297
302
  });
298
303
  });
299
304
  (0, node_test_1.describe)('Concurrent Access Handling', () => {
@@ -157,7 +157,7 @@ const shared_server_utils_js_1 = require("./shared-server-utils.js");
157
157
  node_assert_1.default.strictEqual(response.status, 200);
158
158
  const content = response.data.result.content[0];
159
159
  node_assert_1.default.ok(content.text.includes('Phase Complete!'), 'Should indicate phase completion');
160
- node_assert_1.default.ok(content.text.includes('Next Phase: spec-completeness-review'), 'Should provide next phase');
160
+ node_assert_1.default.ok(content.text.includes('Next Phase: spec-competitor-analysis'), 'Should provide next phase');
161
161
  });
162
162
  (0, node_test_1.it)('should handle incomplete phase with help message', async () => {
163
163
  const axios = require('axios');
@@ -196,12 +196,11 @@ const shared_server_utils_js_1 = require("./shared-server-utils.js");
196
196
  arguments: {
197
197
  workflowType: 'spec',
198
198
  issueNumber: '123',
199
- currentPhase: 'wait-for-pr-review',
199
+ currentPhase: 'retrospective',
200
200
  status: 'complete',
201
201
  evidence: {
202
202
  issueType: 'feature',
203
- prApproved: true,
204
- reviewComplete: true
203
+ retrospectiveComplete: true
205
204
  }
206
205
  }
207
206
  }
@@ -369,7 +368,7 @@ const shared_server_utils_js_1 = require("./shared-server-utils.js");
369
368
  });
370
369
  node_assert_1.default.strictEqual(response.status, 200);
371
370
  content = response.data.result.content[0];
372
- node_assert_1.default.ok(content.text.includes('Next Phase: spec-completeness-review'), 'Should transition to review');
371
+ node_assert_1.default.ok(content.text.includes('Next Phase: spec-competitor-analysis'), 'Should transition to review');
373
372
  // Complete review phase
374
373
  response = await axios.post((0, shared_server_utils_js_1.getMcpEndpoint)(), {
375
374
  jsonrpc: '2.0',
@@ -426,6 +425,25 @@ const shared_server_utils_js_1 = require("./shared-server-utils.js");
426
425
  });
427
426
  node_assert_1.default.strictEqual(response.status, 200);
428
427
  content = response.data.result.content[0];
428
+ node_assert_1.default.ok(content.text.includes('Next Phase: retrospective'), 'Should transition to retrospective');
429
+ // Complete retrospective
430
+ response = await axios.post((0, shared_server_utils_js_1.getMcpEndpoint)(), {
431
+ jsonrpc: '2.0',
432
+ id: 6,
433
+ method: 'tools/call',
434
+ params: {
435
+ name: 'seekCoachingOnNextStep',
436
+ arguments: {
437
+ workflowType: 'spec',
438
+ issueNumber: '999',
439
+ currentPhase: 'retrospective',
440
+ status: 'complete',
441
+ evidence: { issueType: 'feature', retrospectiveComplete: true }
442
+ }
443
+ }
444
+ });
445
+ node_assert_1.default.strictEqual(response.status, 200);
446
+ content = response.data.result.content[0];
429
447
  node_assert_1.default.ok(content.text.includes('Spec Complete!'), 'Should show completion');
430
448
  });
431
449
  });
@@ -75,17 +75,17 @@ const path_1 = require("path");
75
75
  evidence: { issueType: 'feature', specComplete: true }
76
76
  });
77
77
  const duration = Date.now() - startTime;
78
- node_assert_1.default.ok(result.includes('Next Phase: spec-completeness-review'));
78
+ node_assert_1.default.ok(result.includes('Next Phase: spec-competitor-analysis'));
79
79
  node_assert_1.default.ok(duration < 1000, `Phase transition should complete within 1 second (took ${duration}ms)`);
80
80
  });
81
81
  (0, node_test_1.it)('should handle completion messages efficiently', async () => {
82
82
  const startTime = Date.now();
83
83
  const result = await coach.handleCoachingRequest({
84
84
  workflowType: 'spec',
85
- currentPhase: 'wait-for-pr-review',
85
+ currentPhase: 'retrospective',
86
86
  status: 'complete',
87
87
  issueNumber: '123',
88
- evidence: { issueType: 'feature', prApproved: true }
88
+ evidence: { issueType: 'feature', retrospectiveComplete: true }
89
89
  });
90
90
  const duration = Date.now() - startTime;
91
91
  node_assert_1.default.ok(result.includes('Spec Complete!'));
@@ -53,35 +53,44 @@ const path_1 = require("path");
53
53
  });
54
54
  (0, node_test_1.describe)('Phase Flow Logic', () => {
55
55
  (0, node_test_1.it)('should return correct next phase for implement bug workflow', () => {
56
- const phases = ['implement-scoping', 'implement-repro', 'implement-code', 'implement-validate', 'implement-regression', 'implement-completeness-review', 'submit-pr', 'wait-for-pr-review'];
56
+ const phases = ['implement-scoping', 'implement-repro', 'implement-code', 'implement-validate', 'implement-regression', 'implement-completeness-review', 'submit-pr', 'wait-for-pr-review', 'retrospective'];
57
57
  for (let i = 0; i < phases.length - 1; i++) {
58
58
  const nextPhase = (0, phase_flow_js_1.getNextPhase)(phases[i], 'implement', 'bug');
59
59
  node_assert_1.default.strictEqual(nextPhase, phases[i + 1], `Next phase after ${phases[i]} should be ${phases[i + 1]}`);
60
60
  }
61
61
  // Last phase should return null
62
- const lastPhase = (0, phase_flow_js_1.getNextPhase)('wait-for-pr-review', 'implement', 'bug');
63
- node_assert_1.default.strictEqual(lastPhase, null, 'wait-for-pr-review phase should return null as next phase');
62
+ const lastPhase = (0, phase_flow_js_1.getNextPhase)('retrospective', 'implement', 'bug');
63
+ node_assert_1.default.strictEqual(lastPhase, null, 'retrospective phase should return null as next phase');
64
64
  });
65
65
  (0, node_test_1.it)('should return correct next phase for implement feature workflow', () => {
66
- const phases = ['implement-scoping', 'implement-spike', 'implement-code', 'implement-validate', 'implement-smoke', 'implement-regression', 'implement-completeness-review', 'submit-pr', 'wait-for-pr-review'];
66
+ const phases = ['implement-scoping', 'implement-spike', 'implement-code', 'implement-validate', 'implement-smoke', 'implement-regression', 'implement-completeness-review', 'submit-pr', 'wait-for-pr-review', 'retrospective'];
67
67
  for (let i = 0; i < phases.length - 1; i++) {
68
68
  const nextPhase = (0, phase_flow_js_1.getNextPhase)(phases[i], 'implement', 'feature');
69
69
  node_assert_1.default.strictEqual(nextPhase, phases[i + 1], `Next phase after ${phases[i]} should be ${phases[i + 1]}`);
70
70
  }
71
+ // Last phase should return null
72
+ const lastPhase = (0, phase_flow_js_1.getNextPhase)('retrospective', 'implement', 'feature');
73
+ node_assert_1.default.strictEqual(lastPhase, null, 'retrospective phase should return null as next phase');
71
74
  });
72
75
  (0, node_test_1.it)('should return correct next phase for spec workflow', () => {
73
- const phases = ['spec-spec', 'spec-completeness-review', 'submit-pr', 'wait-for-pr-review'];
76
+ const phases = ['spec-spec', 'spec-competitor-analysis', 'spec-completeness-review', 'submit-pr', 'wait-for-pr-review', 'retrospective'];
74
77
  for (let i = 0; i < phases.length - 1; i++) {
75
78
  const nextPhase = (0, phase_flow_js_1.getNextPhase)(phases[i], 'spec');
76
79
  node_assert_1.default.strictEqual(nextPhase, phases[i + 1], `Next phase after ${phases[i]} should be ${phases[i + 1]}`);
77
80
  }
81
+ // Last phase should return null
82
+ const lastPhase = (0, phase_flow_js_1.getNextPhase)('retrospective', 'spec');
83
+ node_assert_1.default.strictEqual(lastPhase, null, 'retrospective phase should return null as next phase');
78
84
  });
79
85
  (0, node_test_1.it)('should return correct next phase for design workflow', () => {
80
- const phases = ['design-design', 'design-completeness-review', 'submit-pr', 'wait-for-pr-review'];
86
+ const phases = ['design-design', 'design-completeness-review', 'submit-pr', 'wait-for-pr-review', 'retrospective'];
81
87
  for (let i = 0; i < phases.length - 1; i++) {
82
88
  const nextPhase = (0, phase_flow_js_1.getNextPhase)(phases[i], 'design');
83
89
  node_assert_1.default.strictEqual(nextPhase, phases[i + 1], `Next phase after ${phases[i]} should be ${phases[i + 1]}`);
84
90
  }
91
+ // Last phase should return null
92
+ const lastPhase = (0, phase_flow_js_1.getNextPhase)('retrospective', 'design');
93
+ node_assert_1.default.strictEqual(lastPhase, null, 'retrospective phase should return null as next phase');
85
94
  });
86
95
  (0, node_test_1.it)('should validate phases correctly for each workflow type', () => {
87
96
  // Test implement workflow phases
@@ -110,16 +119,16 @@ const path_1 = require("path");
110
119
  });
111
120
  (0, node_test_1.it)('should return correct phases for each workflow type', () => {
112
121
  const bugPhases = (0, phase_flow_js_1.getPhasesForWorkflow)('implement', 'bug');
113
- const expectedBugPhases = ['implement-scoping', 'implement-repro', 'implement-code', 'implement-validate', 'implement-regression', 'implement-completeness-review', 'submit-pr', 'wait-for-pr-review'];
122
+ const expectedBugPhases = ['implement-scoping', 'implement-repro', 'implement-code', 'implement-validate', 'implement-regression', 'implement-completeness-review', 'submit-pr', 'wait-for-pr-review', 'retrospective'];
114
123
  node_assert_1.default.deepStrictEqual(bugPhases, expectedBugPhases);
115
124
  const featurePhases = (0, phase_flow_js_1.getPhasesForWorkflow)('implement', 'feature');
116
- const expectedFeaturePhases = ['implement-scoping', 'implement-spike', 'implement-code', 'implement-validate', 'implement-smoke', 'implement-regression', 'implement-completeness-review', 'submit-pr', 'wait-for-pr-review'];
125
+ const expectedFeaturePhases = ['implement-scoping', 'implement-spike', 'implement-code', 'implement-validate', 'implement-smoke', 'implement-regression', 'implement-completeness-review', 'submit-pr', 'wait-for-pr-review', 'retrospective'];
117
126
  node_assert_1.default.deepStrictEqual(featurePhases, expectedFeaturePhases);
118
127
  const specPhases = (0, phase_flow_js_1.getPhasesForWorkflow)('spec');
119
- const expectedSpecPhases = ['spec-spec', 'spec-completeness-review', 'submit-pr', 'wait-for-pr-review'];
128
+ const expectedSpecPhases = ['spec-spec', 'spec-competitor-analysis', 'spec-completeness-review', 'submit-pr', 'wait-for-pr-review', 'retrospective'];
120
129
  node_assert_1.default.deepStrictEqual(specPhases, expectedSpecPhases);
121
130
  const designPhases = (0, phase_flow_js_1.getPhasesForWorkflow)('design');
122
- const expectedDesignPhases = ['design-design', 'design-completeness-review', 'submit-pr', 'wait-for-pr-review'];
131
+ const expectedDesignPhases = ['design-design', 'design-completeness-review', 'submit-pr', 'wait-for-pr-review', 'retrospective'];
123
132
  node_assert_1.default.deepStrictEqual(designPhases, expectedDesignPhases);
124
133
  });
125
134
  (0, node_test_1.it)('should throw error for invalid workflow types', () => {
@@ -213,16 +222,16 @@ const path_1 = require("path");
213
222
  evidence: { issueType: 'feature', specComplete: true }
214
223
  });
215
224
  node_assert_1.default.ok(result.includes('Phase Complete!'), 'Should indicate phase completion');
216
- node_assert_1.default.ok(result.includes('Next Phase: spec-completeness-review'), 'Should provide next phase instructions');
217
- node_assert_1.default.ok(result.includes('Phase: Spec-Completeness-Review'), 'Should include next phase content');
225
+ node_assert_1.default.ok(result.includes('Next Phase: spec-competitor-analysis'), 'Should provide next phase instructions');
226
+ node_assert_1.default.ok(result.includes('Phase: spec-competitor-analysis'), 'Should include next phase content');
218
227
  });
219
228
  (0, node_test_1.it)('should provide completion message for wait-for-pr-review phase', async () => {
220
229
  const result = await coach.handleCoachingRequest({
221
230
  workflowType: 'spec',
222
- currentPhase: 'wait-for-pr-review',
231
+ currentPhase: 'retrospective',
223
232
  status: 'complete',
224
233
  issueNumber: '123',
225
- evidence: { issueType: 'feature', prApproved: true }
234
+ evidence: { issueType: 'feature', retrospectiveComplete: true }
226
235
  });
227
236
  node_assert_1.default.ok(result.includes('Spec Complete!'), 'Should show workflow completion message');
228
237
  node_assert_1.default.ok(result.includes('Congratulations!'), 'Should include congratulations');
@@ -326,10 +335,10 @@ const path_1 = require("path");
326
335
  for (const workflow of workflows) {
327
336
  const result = await coach.handleCoachingRequest({
328
337
  workflowType: workflow.type,
329
- currentPhase: 'wait-for-pr-review',
338
+ currentPhase: 'retrospective',
330
339
  status: 'complete',
331
340
  issueNumber: '123',
332
- evidence: { issueType: 'feature', prApproved: true }
341
+ evidence: { issueType: 'feature', retrospectiveComplete: true }
333
342
  });
334
343
  node_assert_1.default.ok(result.includes(workflow.expectedText), `${workflow.type} workflow should show correct accomplishments`);
335
344
  }
@@ -398,6 +407,15 @@ const path_1 = require("path");
398
407
  issueNumber,
399
408
  evidence: { issueType: 'feature', specComplete: true }
400
409
  });
410
+ node_assert_1.default.ok(result.includes('Next Phase: spec-competitor-analysis'), 'Should transition to competitor analysis');
411
+ // Complete competitor analysis
412
+ result = await coach.handleCoachingRequest({
413
+ workflowType,
414
+ currentPhase: 'spec-competitor-analysis',
415
+ status: 'complete',
416
+ issueNumber,
417
+ evidence: { issueType: 'feature', competitorAnalysisComplete: true }
418
+ });
401
419
  node_assert_1.default.ok(result.includes('Next Phase: spec-completeness-review'), 'Should transition to completeness review');
402
420
  // Complete completeness review
403
421
  result = await coach.handleCoachingRequest({
@@ -425,14 +443,23 @@ const path_1 = require("path");
425
443
  issueNumber,
426
444
  evidence: { issueType: 'feature', prApproved: true }
427
445
  });
446
+ node_assert_1.default.ok(result.includes('Next Phase: retrospective'), 'Should transition to retrospective');
447
+ // Complete retrospective
448
+ result = await coach.handleCoachingRequest({
449
+ workflowType,
450
+ currentPhase: 'retrospective',
451
+ status: 'complete',
452
+ issueNumber,
453
+ evidence: { issueType: 'feature', retrospectiveComplete: true }
454
+ });
428
455
  node_assert_1.default.ok(result.includes('Spec Complete!'), 'Should show completion message');
429
456
  });
430
457
  (0, node_test_1.it)('should complete full implement bug workflow', async () => {
431
458
  const issueNumber = '456';
432
459
  const workflowType = 'implement';
433
460
  const issueType = 'bug';
434
- // Test key phases in bug workflow
435
- const phases = ['implement-scoping', 'implement-repro', 'implement-code', 'wait-for-pr-review'];
461
+ // Test key phases in bug workflow including retrospective
462
+ const phases = ['implement-scoping', 'implement-repro', 'implement-code', 'wait-for-pr-review', 'retrospective'];
436
463
  for (let i = 0; i < phases.length; i++) {
437
464
  const phase = phases[i];
438
465
  const isLast = i === phases.length - 1;
@@ -25,7 +25,9 @@ async function testPRReviewPhaseFlow() {
25
25
  const nextAfterSubmitPR = (0, phase_flow_js_1.getNextPhase)('submit-pr', 'implement', 'bug');
26
26
  node_assert_1.strict.equal(nextAfterSubmitPR, 'wait-for-pr-review', 'After submit-pr should go to wait-for-pr-review');
27
27
  const nextAfterWaitPR = (0, phase_flow_js_1.getNextPhase)('wait-for-pr-review', 'implement', 'bug');
28
- node_assert_1.strict.equal(nextAfterWaitPR, null, 'wait-for-pr-review should be the last phase');
28
+ node_assert_1.strict.equal(nextAfterWaitPR, 'retrospective', 'After wait-for-pr-review should go to retrospective');
29
+ const nextAfterRetrospective = (0, phase_flow_js_1.getNextPhase)('retrospective', 'implement', 'bug');
30
+ node_assert_1.strict.equal(nextAfterRetrospective, null, 'retrospective should be the last phase');
29
31
  console.log('✅ PR review phase flow tests passed');
30
32
  return true;
31
33
  }
@@ -187,8 +189,10 @@ async function testRealWorldPRReviewScenario() {
187
189
  currentPhase = nextPhase;
188
190
  }
189
191
  // Test PR review completion (approved)
190
- const finalPhase = (0, phase_flow_js_1.getNextPhase)('wait-for-pr-review', workflowType, issueType);
191
- node_assert_1.strict.equal(finalPhase, null, 'wait-for-pr-review should be final phase when approved');
192
+ const nextPhaseAfterPR = (0, phase_flow_js_1.getNextPhase)('wait-for-pr-review', workflowType, issueType);
193
+ node_assert_1.strict.equal(nextPhaseAfterPR, 'retrospective', 'wait-for-pr-review should go to retrospective when approved');
194
+ const finalPhase = (0, phase_flow_js_1.getNextPhase)('retrospective', workflowType, issueType);
195
+ node_assert_1.strict.equal(finalPhase, null, 'retrospective should be final phase when approved');
192
196
  // Test PR review with changes requested (failure scenario)
193
197
  const failurePhase = (0, phase_flow_js_1.getPhaseOnFailure)('wait-for-pr-review', workflowType, issueType);
194
198
  node_assert_1.strict.equal(failurePhase, 'address-pr-feedback', 'PR changes requested should route to address-pr-feedback');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fraim-framework",
3
- "version": "2.0.49",
3
+ "version": "2.0.52",
4
4
  "description": "FRAIM v2: Framework for Rigor-based AI Management - Transform from solo developer to AI manager orchestrating production-ready code with enterprise-grade discipline",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -21,7 +21,7 @@
21
21
  "view-signups": "tsx scripts/view-signups.ts",
22
22
  "fraim:init": "npm run build && node bin/fraim.js init",
23
23
  "fraim:sync": "node bin/fraim.js sync",
24
- "postinstall": "fraim sync || echo 'FRAIM setup skipped.'",
24
+ "postinstall": "fraim sync --skip-updates || echo 'FRAIM setup skipped.'",
25
25
  "prepublishOnly": "npm run build",
26
26
  "release": "npm version patch && npm publish",
27
27
  "test-smoke-ci": "tsx --test tests/test-genericization.ts tests/test-cli.ts tests/test-stub-registry.ts tests/test-sync-stubs.ts",