fraim-framework 2.0.71 → 2.0.73

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,165 @@
1
+ "use strict";
2
+ /**
3
+ * LocalRegistryResolver
4
+ *
5
+ * Resolves registry file requests by checking for local overrides first,
6
+ * then falling back to remote registry. Handles inheritance via InheritanceParser.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.LocalRegistryResolver = void 0;
10
+ const fs_1 = require("fs");
11
+ const path_1 = require("path");
12
+ const inheritance_parser_1 = require("./inheritance-parser");
13
+ class LocalRegistryResolver {
14
+ constructor(options) {
15
+ this.workspaceRoot = options.workspaceRoot;
16
+ this.remoteContentResolver = options.remoteContentResolver;
17
+ this.parser = new inheritance_parser_1.InheritanceParser(options.maxDepth);
18
+ }
19
+ /**
20
+ * Check if a local override exists for the given path
21
+ */
22
+ hasLocalOverride(path) {
23
+ const overridePath = this.getOverridePath(path);
24
+ const exists = (0, fs_1.existsSync)(overridePath);
25
+ console.error(`[LocalRegistryResolver] hasLocalOverride(${path}) -> ${overridePath} -> ${exists}`);
26
+ return exists;
27
+ }
28
+ /**
29
+ * Get the full path to a local override file
30
+ */
31
+ getOverridePath(path) {
32
+ return (0, path_1.join)(this.workspaceRoot, '.fraim/overrides', path);
33
+ }
34
+ /**
35
+ * Read local override file content
36
+ */
37
+ readLocalOverride(path) {
38
+ const overridePath = this.getOverridePath(path);
39
+ try {
40
+ return (0, fs_1.readFileSync)(overridePath, 'utf-8');
41
+ }
42
+ catch (error) {
43
+ throw new Error(`Failed to read local override: ${path}. ${error.message}`);
44
+ }
45
+ }
46
+ /**
47
+ * Resolve inheritance in local override content
48
+ */
49
+ async resolveInheritance(content, currentPath) {
50
+ // Check if content has imports
51
+ const parseResult = this.parser.parse(content);
52
+ if (!parseResult.hasImports) {
53
+ return { content, imports: [] };
54
+ }
55
+ // Resolve imports
56
+ try {
57
+ const resolved = await this.parser.resolve(content, currentPath, {
58
+ fetchParent: this.remoteContentResolver,
59
+ maxDepth: 5
60
+ });
61
+ return {
62
+ content: resolved,
63
+ imports: parseResult.imports
64
+ };
65
+ }
66
+ catch (error) {
67
+ if (error instanceof inheritance_parser_1.InheritanceError) {
68
+ throw error;
69
+ }
70
+ throw new Error(`Failed to resolve inheritance for ${currentPath}: ${error.message}`);
71
+ }
72
+ }
73
+ /**
74
+ * Generate metadata comment for resolved content
75
+ */
76
+ generateMetadata(result) {
77
+ if (result.source === 'remote') {
78
+ return '';
79
+ }
80
+ if (result.inherited && result.imports && result.imports.length > 0) {
81
+ return `<!-- 📝 Using local override (inherited from: ${result.imports.join(', ')}) -->\n\n`;
82
+ }
83
+ return `<!-- 📝 Using local override -->\n\n`;
84
+ }
85
+ /**
86
+ * Resolve a registry file request
87
+ *
88
+ * Resolution order:
89
+ * 1. Check for local override in .fraim/overrides/
90
+ * 2. If found, read and resolve inheritance
91
+ * 3. If not found, fetch from remote
92
+ *
93
+ * @param path - Registry path (e.g., "workflows/product-building/spec.md")
94
+ * @returns Resolved file with metadata
95
+ */
96
+ async resolveFile(path) {
97
+ console.error(`[LocalRegistryResolver] ===== resolveFile called for: ${path} =====`);
98
+ // Check for local override
99
+ if (!this.hasLocalOverride(path)) {
100
+ // No override, fetch from remote
101
+ try {
102
+ const content = await this.remoteContentResolver(path);
103
+ return {
104
+ content,
105
+ source: 'remote',
106
+ inherited: false
107
+ };
108
+ }
109
+ catch (error) {
110
+ throw new Error(`Failed to fetch from remote: ${path}. ${error.message}`);
111
+ }
112
+ }
113
+ // Read local override
114
+ let localContent;
115
+ try {
116
+ localContent = this.readLocalOverride(path);
117
+ }
118
+ catch (error) {
119
+ // If local read fails, fall back to remote
120
+ console.warn(`Local override read failed, falling back to remote: ${path}`);
121
+ const content = await this.remoteContentResolver(path);
122
+ return {
123
+ content,
124
+ source: 'remote',
125
+ inherited: false
126
+ };
127
+ }
128
+ // Resolve inheritance
129
+ let resolved;
130
+ try {
131
+ console.error(`[LocalRegistryResolver] Resolving inheritance for ${path}`);
132
+ console.error(`[LocalRegistryResolver] Local content length: ${localContent.length} chars`);
133
+ console.error(`[LocalRegistryResolver] Local content preview: ${localContent.substring(0, 200)}`);
134
+ resolved = await this.resolveInheritance(localContent, path);
135
+ console.error(`[LocalRegistryResolver] Inheritance resolved: ${resolved.imports.length} imports`);
136
+ console.error(`[LocalRegistryResolver] Resolved content length: ${resolved.content.length} chars`);
137
+ console.error(`[LocalRegistryResolver] Resolved content preview: ${resolved.content.substring(0, 200)}`);
138
+ }
139
+ catch (error) {
140
+ // If inheritance resolution fails, fall back to remote
141
+ console.error(`❌ Inheritance resolution failed for ${path}:`, error);
142
+ const content = await this.remoteContentResolver(path);
143
+ return {
144
+ content,
145
+ source: 'remote',
146
+ inherited: false
147
+ };
148
+ }
149
+ // Build result
150
+ const result = {
151
+ content: resolved.content,
152
+ source: 'local',
153
+ inherited: resolved.imports.length > 0,
154
+ imports: resolved.imports.length > 0 ? resolved.imports : undefined
155
+ };
156
+ // Add metadata comment
157
+ const metadata = this.generateMetadata(result);
158
+ if (metadata) {
159
+ result.metadata = metadata;
160
+ result.content = metadata + result.content;
161
+ }
162
+ return result;
163
+ }
164
+ }
165
+ exports.LocalRegistryResolver = LocalRegistryResolver;
@@ -27,6 +27,7 @@ const crypto_1 = require("crypto");
27
27
  const axios_1 = __importDefault(require("axios"));
28
28
  const provider_utils_1 = require("../core/utils/provider-utils");
29
29
  const object_utils_1 = require("../core/utils/object-utils");
30
+ const local_registry_resolver_1 = require("../core/utils/local-registry-resolver");
30
31
  /**
31
32
  * Handle template substitution logic separately for better testability
32
33
  */
@@ -80,22 +81,35 @@ class FraimTemplateEngine {
80
81
  const filename = this.workingStyle === 'Conversation' ? 'delivery-conversation.json' : 'delivery-pr.json';
81
82
  try {
82
83
  let content = null;
83
- if (this.projectRoot) {
84
- const deliveryPath = (0, path_1.join)(this.projectRoot, 'registry', 'providers', filename);
85
- if ((0, fs_1.existsSync)(deliveryPath)) {
86
- content = (0, fs_1.readFileSync)(deliveryPath, 'utf-8');
87
- }
88
- }
84
+ // Try framework installation directory first (relative to this file)
85
+ // This file is in dist/src/local-mcp-server/, so go up to framework root
86
+ const frameworkRoot = (0, path_1.join)(__dirname, '..', '..', '..');
87
+ const frameworkPath = (0, path_1.join)(frameworkRoot, 'registry', 'providers', filename);
88
+ if ((0, fs_1.existsSync)(frameworkPath)) {
89
+ content = (0, fs_1.readFileSync)(frameworkPath, 'utf-8');
90
+ this.logFn(`✅ Loaded delivery templates from framework: ${frameworkPath}`);
91
+ }
92
+ // Fallback: try node_modules if not found in framework root
89
93
  if (!content) {
90
94
  const nodeModulesPath = (0, path_1.join)(process.cwd(), 'node_modules', '@fraim', 'framework', 'registry', 'providers', filename);
91
95
  if ((0, fs_1.existsSync)(nodeModulesPath)) {
92
96
  content = (0, fs_1.readFileSync)(nodeModulesPath, 'utf-8');
97
+ this.logFn(`✅ Loaded delivery templates from node_modules: ${nodeModulesPath}`);
98
+ }
99
+ }
100
+ // Last resort: try project root (for custom overrides)
101
+ if (!content && this.projectRoot) {
102
+ const deliveryPath = (0, path_1.join)(this.projectRoot, 'registry', 'providers', filename);
103
+ if ((0, fs_1.existsSync)(deliveryPath)) {
104
+ content = (0, fs_1.readFileSync)(deliveryPath, 'utf-8');
105
+ this.logFn(`✅ Loaded delivery templates from project: ${deliveryPath}`);
93
106
  }
94
107
  }
95
108
  if (content) {
96
109
  this.deliveryTemplatesCache = JSON.parse(content);
97
110
  return this.deliveryTemplatesCache;
98
111
  }
112
+ this.logFn(`⚠️ Could not find delivery templates: ${filename}`);
99
113
  return null;
100
114
  }
101
115
  catch (error) {
@@ -121,18 +135,26 @@ class FraimTemplateEngine {
121
135
  return this.providerTemplatesCache[provider];
122
136
  try {
123
137
  let content = null;
124
- if (this.projectRoot) {
125
- const providerPath = (0, path_1.join)(this.projectRoot, 'registry', 'providers', `${provider}.json`);
126
- if ((0, fs_1.existsSync)(providerPath)) {
127
- content = (0, fs_1.readFileSync)(providerPath, 'utf-8');
128
- }
138
+ // Try framework installation directory first (relative to this file)
139
+ const frameworkRoot = (0, path_1.join)(__dirname, '..', '..', '..');
140
+ const frameworkPath = (0, path_1.join)(frameworkRoot, 'registry', 'providers', `${provider}.json`);
141
+ if ((0, fs_1.existsSync)(frameworkPath)) {
142
+ content = (0, fs_1.readFileSync)(frameworkPath, 'utf-8');
129
143
  }
144
+ // Fallback: try node_modules
130
145
  if (!content) {
131
146
  const nodeModulesPath = (0, path_1.join)(process.cwd(), 'node_modules', '@fraim', 'framework', 'registry', 'providers', `${provider}.json`);
132
147
  if ((0, fs_1.existsSync)(nodeModulesPath)) {
133
148
  content = (0, fs_1.readFileSync)(nodeModulesPath, 'utf-8');
134
149
  }
135
150
  }
151
+ // Last resort: try project root (for custom overrides)
152
+ if (!content && this.projectRoot) {
153
+ const providerPath = (0, path_1.join)(this.projectRoot, 'registry', 'providers', `${provider}.json`);
154
+ if ((0, fs_1.existsSync)(providerPath)) {
155
+ content = (0, fs_1.readFileSync)(providerPath, 'utf-8');
156
+ }
157
+ }
136
158
  if (content) {
137
159
  const templates = JSON.parse(content);
138
160
  this.providerTemplatesCache[provider] = templates;
@@ -178,6 +200,7 @@ class FraimLocalMCPServer {
178
200
  this.machineInfo = null;
179
201
  this.repoInfo = null;
180
202
  this.engine = null;
203
+ this.registryResolver = null;
181
204
  this.remoteUrl = process.env.FRAIM_REMOTE_URL || 'https://fraim.wellnessatwork.me';
182
205
  this.apiKey = process.env.FRAIM_API_KEY || '';
183
206
  this.localVersion = this.detectLocalVersion();
@@ -349,6 +372,10 @@ class FraimLocalMCPServer {
349
372
  if (this.repoInfo) {
350
373
  return this.repoInfo;
351
374
  }
375
+ // Ensure config is loaded before trying to detect repo info
376
+ if (!this.config) {
377
+ this.loadConfig();
378
+ }
352
379
  try {
353
380
  const projectDir = this.findProjectRoot() || process.cwd();
354
381
  // Try to get git remote URL
@@ -464,6 +491,112 @@ class FraimLocalMCPServer {
464
491
  }
465
492
  return this.engine.substituteTemplates(content);
466
493
  }
494
+ /**
495
+ * Initialize the LocalRegistryResolver for override resolution
496
+ */
497
+ getRegistryResolver() {
498
+ if (!this.registryResolver) {
499
+ const projectRoot = this.findProjectRoot();
500
+ this.log(`🔍 getRegistryResolver: projectRoot = ${projectRoot}`);
501
+ if (!projectRoot) {
502
+ this.log('⚠️ No project root found, override resolution disabled');
503
+ // Return a resolver that always falls back to remote
504
+ this.registryResolver = new local_registry_resolver_1.LocalRegistryResolver({
505
+ workspaceRoot: process.cwd(),
506
+ remoteContentResolver: async (path) => {
507
+ throw new Error('No project root available');
508
+ }
509
+ });
510
+ }
511
+ else {
512
+ this.registryResolver = new local_registry_resolver_1.LocalRegistryResolver({
513
+ workspaceRoot: projectRoot,
514
+ remoteContentResolver: async (path) => {
515
+ // Fetch parent content from remote for inheritance
516
+ this.log(`🔄 Remote content resolver: fetching ${path}`);
517
+ let request;
518
+ if (path.startsWith('workflows/')) {
519
+ // Extract workflow name from path: workflows/category/name.md -> name
520
+ const pathParts = path.replace('workflows/', '').replace('.md', '').split('/');
521
+ const workflowName = pathParts[pathParts.length - 1]; // Get last part (name)
522
+ this.log(`🔄 Fetching workflow: ${workflowName}`);
523
+ request = {
524
+ jsonrpc: '2.0',
525
+ id: (0, crypto_1.randomUUID)(),
526
+ method: 'tools/call',
527
+ params: {
528
+ name: 'get_fraim_workflow',
529
+ arguments: { workflow: workflowName }
530
+ }
531
+ };
532
+ }
533
+ else {
534
+ // For non-workflow files (templates, rules, etc.), use get_fraim_file
535
+ this.log(`🔄 Fetching file: ${path}`);
536
+ request = {
537
+ jsonrpc: '2.0',
538
+ id: (0, crypto_1.randomUUID)(),
539
+ method: 'tools/call',
540
+ params: {
541
+ name: 'get_fraim_file',
542
+ arguments: { path }
543
+ }
544
+ };
545
+ }
546
+ const response = await this.proxyToRemote(request);
547
+ if (response.error) {
548
+ this.logError(`❌ Remote content resolver failed: ${response.error.message}`);
549
+ throw new Error(`Failed to fetch parent: ${response.error.message}`);
550
+ }
551
+ // Extract content from MCP response format
552
+ if (response.result?.content && Array.isArray(response.result.content)) {
553
+ const textContent = response.result.content.find((c) => c.type === 'text');
554
+ if (textContent?.text) {
555
+ this.log(`✅ Remote content resolver: fetched ${textContent.text.length} chars`);
556
+ return textContent.text;
557
+ }
558
+ }
559
+ this.logError(`❌ Remote content resolver: no content in response for ${path}`);
560
+ this.logError(`Response: ${JSON.stringify(response, null, 2)}`);
561
+ throw new Error(`No content in remote response for ${path}`);
562
+ }
563
+ });
564
+ }
565
+ }
566
+ return this.registryResolver;
567
+ }
568
+ /**
569
+ * Determine workflow category from workflow name
570
+ */
571
+ getWorkflowCategory(workflowName) {
572
+ // Product development workflows
573
+ const productWorkflows = [
574
+ 'prep-issue', 'spec', 'design', 'implement', 'test', 'resolve',
575
+ 'prototype', 'refactor', 'iterate-on-pr-comments', 'retrospect'
576
+ ];
577
+ // Customer development workflows
578
+ const customerWorkflows = [
579
+ 'linkedin-outreach', 'customer-interview', 'insight-analysis',
580
+ 'insight-triage', 'interview-preparation', 'strategic-brainstorming',
581
+ 'thank-customers', 'user-survey-dispatch', 'users-to-target', 'weekly-newsletter'
582
+ ];
583
+ // Business development workflows
584
+ const businessWorkflows = [
585
+ 'partnership-outreach', 'investor-pitch', 'create-business-plan',
586
+ 'ideate-business-opportunity', 'price-product'
587
+ ];
588
+ if (productWorkflows.includes(workflowName)) {
589
+ return 'product-building';
590
+ }
591
+ else if (customerWorkflows.includes(workflowName)) {
592
+ return 'customer-development';
593
+ }
594
+ else if (businessWorkflows.includes(workflowName)) {
595
+ return 'business-development';
596
+ }
597
+ // Default to product-building for unknown workflows
598
+ return 'product-building';
599
+ }
467
600
  /**
468
601
  * Process template substitution in MCP response
469
602
  */
@@ -522,16 +655,20 @@ class FraimLocalMCPServer {
522
655
  this.log(`[req:${requestId}] Auto-detected and injected repo info: ${args.repo.owner}/${args.repo.name}`);
523
656
  }
524
657
  else {
525
- // If detection fails completely, return error instead of sending garbage
526
- this.logError(`[req:${requestId}] Could not detect repo info and no config available`);
527
- return {
528
- jsonrpc: '2.0',
529
- id: request.id,
530
- error: {
531
- code: -32603,
532
- message: 'Failed to detect repository information. Please ensure you are in a git repository or have .fraim/config.json configured with repository details.'
533
- }
534
- };
658
+ // If detection fails, use agent-provided values (if any)
659
+ if (!args.repo || !args.repo.url) {
660
+ // Only return error if agent didn't provide repo info either
661
+ this.logError(`[req:${requestId}] Could not detect repo info and no repo info provided by agent`);
662
+ return {
663
+ jsonrpc: '2.0',
664
+ id: request.id,
665
+ error: {
666
+ code: -32603,
667
+ message: 'Failed to detect repository information. Please ensure you are in a git repository or have .fraim/config.json configured with repository details, or provide repo info in fraim_connect arguments.'
668
+ }
669
+ };
670
+ }
671
+ this.log(`[req:${requestId}] Using agent-provided repo info: ${args.repo.owner}/${args.repo.name}`);
535
672
  }
536
673
  // Update the request with injected info
537
674
  request.params.arguments = args;
@@ -640,6 +777,94 @@ class FraimLocalMCPServer {
640
777
  this.log(`📤 ${request.method} → ${processedResponse.error ? 'ERROR' : 'OK'}`);
641
778
  return processedResponse;
642
779
  }
780
+ // Intercept get_fraim_workflow and get_fraim_file for override resolution
781
+ if (request.method === 'tools/call' &&
782
+ (request.params?.name === 'get_fraim_workflow' ||
783
+ request.params?.name === 'get_fraim_file')) {
784
+ try {
785
+ const toolName = request.params.name;
786
+ const args = request.params.arguments || {};
787
+ // Extract the requested path
788
+ let requestedPath;
789
+ if (toolName === 'get_fraim_workflow') {
790
+ // Convert workflow name to path (e.g., "spec" -> "workflows/product-building/spec.md")
791
+ const workflowName = args.workflow;
792
+ if (!workflowName) {
793
+ this.log('⚠️ No workflow name provided in get_fraim_workflow');
794
+ }
795
+ else {
796
+ // Determine workflow category from name
797
+ const category = this.getWorkflowCategory(workflowName);
798
+ requestedPath = `workflows/${category}/${workflowName}.md`;
799
+ this.log(`🔍 Checking for override: ${requestedPath}`);
800
+ const resolver = this.getRegistryResolver();
801
+ const hasOverride = resolver.hasLocalOverride(requestedPath);
802
+ this.log(`🔍 hasLocalOverride(${requestedPath}) = ${hasOverride}`);
803
+ if (hasOverride) {
804
+ this.log(`✅ Local override found: ${requestedPath}`);
805
+ const resolved = await resolver.resolveFile(requestedPath);
806
+ this.log(`📝 Override resolved (source: ${resolved.source}, inherited: ${resolved.inherited})`);
807
+ // Build MCP response with resolved content
808
+ const response = {
809
+ jsonrpc: '2.0',
810
+ id: request.id,
811
+ result: {
812
+ content: [
813
+ {
814
+ type: 'text',
815
+ text: resolved.content
816
+ }
817
+ ]
818
+ }
819
+ };
820
+ // Apply template substitution
821
+ const processedResponse = this.processResponse(response);
822
+ this.log(`📤 ${request.method} → OK`);
823
+ return processedResponse;
824
+ }
825
+ }
826
+ }
827
+ else if (toolName === 'get_fraim_file') {
828
+ requestedPath = args.path;
829
+ if (!requestedPath) {
830
+ this.log('⚠️ No path provided in get_fraim_file');
831
+ }
832
+ else {
833
+ this.log(`🔍 Checking for override: ${requestedPath}`);
834
+ const resolver = this.getRegistryResolver();
835
+ const hasOverride = resolver.hasLocalOverride(requestedPath);
836
+ this.log(`🔍 hasLocalOverride(${requestedPath}) = ${hasOverride}`);
837
+ if (hasOverride) {
838
+ this.log(`✅ Local override found: ${requestedPath}`);
839
+ const resolved = await resolver.resolveFile(requestedPath);
840
+ this.log(`📝 Override resolved (source: ${resolved.source}, inherited: ${resolved.inherited})`);
841
+ // Build MCP response with resolved content
842
+ const response = {
843
+ jsonrpc: '2.0',
844
+ id: request.id,
845
+ result: {
846
+ content: [
847
+ {
848
+ type: 'text',
849
+ text: resolved.content
850
+ }
851
+ ]
852
+ }
853
+ };
854
+ // Apply template substitution
855
+ const processedResponse = this.processResponse(response);
856
+ this.log(`📤 ${request.method} → OK`);
857
+ return processedResponse;
858
+ }
859
+ }
860
+ }
861
+ }
862
+ catch (error) {
863
+ this.logError(`Override resolution failed: ${error.message}`);
864
+ this.log('⚠️ Falling back to remote');
865
+ // Fall through to proxy to remote
866
+ }
867
+ }
643
868
  // Proxy to remote server
644
869
  const response = await this.proxyToRemote(request);
645
870
  // Process template substitution (config vars, platform actions, delivery templates)
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  /**
4
4
  * FRAIM Framework - Smart Entry Point
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fraim-framework",
3
- "version": "2.0.71",
3
+ "version": "2.0.73",
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": {
package/CHANGELOG.md DELETED
@@ -1,76 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to this project will be documented in this file.
4
-
5
-
6
- ## [2.1.0] - 2026-02-04
7
-
8
- ### 🔄 Workflow Refinement
9
- - **Consolidated Workflows**: Inlined all phase content into main workflow files (`spec.md`, `design.md`, `implement.md`) for better context retention and reduced file scatter.
10
- - **Removed Redundant Files**: Deleted separate phase folders (`design-phases`, `implement-phases`, `spec-phases`, etc.) to streamline repository structure.
11
- - **Terminology Update**: Renamed "AI Coach" to "AI Mentor" across all workflows to align with new branding.
12
- - **Enhanced Spec Workflow**: Added `spec-competitor-analysis` phase and inlined validation steps.
13
- - **Retrospective Integration**: Inlined retrospective phase content into all major workflows.
14
-
15
- ## [2.0.0] - 2024-12-19
16
-
17
- ### 🚀 Major Release: FRAIM v2 - The Future of AI-Assisted Development
18
-
19
- #### ✨ New Features
20
- - **Complete Generic Framework**: Removed all Ashley-specific IP, making FRAIM truly universal
21
- - **Enhanced Rule System**: 13 comprehensive rule files covering all aspects of AI agent management
22
- - **Simplified Label System**: Streamlined to 9 essential labels matching real-world usage
23
- - **Spec Workflow**: Added specification phase for requirements and user experience definition
24
- - **Timeout Management**: Advanced timeout scripts with output visibility for long-running tasks
25
- - **Evidence-Based Validation**: Mandatory test evidence collection and validation
26
- - **Systematic Debugging**: Structured debugging patterns with learning capture
27
-
28
- #### 🔧 Improvements
29
- - **Single Install Method**: Simplified to `npm install -g fraim-framework`
30
- - **Better Documentation**: Comprehensive README with marketing-style positioning
31
- - **Example Test Cases**: Complete example with tagging system and documentation
32
- - **TypeScript Support**: Full TypeScript compilation and type safety
33
- - **Git Safety**: Safe Git commands preventing agent hangs
34
- - **Merge Requirements**: Advanced branch management with conflict resolution
35
-
36
- #### 🛡️ Security & Reliability
37
- - **Agent Integrity Rules**: Prevents "fake it till you make it" behavior
38
- - **Test Ethics**: Mandatory evidence collection and validation
39
- - **Communication Standards**: Clear accountability and progress reporting
40
- - **Architecture Discipline**: Clean separation of concerns and technical debt prevention
41
-
42
- #### 📚 Documentation
43
- - **Marketing README**: Compelling documentation positioning FRAIM as the future
44
- - **Problem-Solution Mapping**: Each rule clearly mapped to specific problems
45
- - **Human-Agent Parallels**: Clear comparison between human and AI development
46
- - **Success Stories**: Realistic testimonials and quantified benefits
47
-
48
- #### 🎯 Workflow Enhancements
49
- - **RIGOR Methodology**: Reviews, Isolation, GitOps, Observability, Retrospectives
50
- - **Phase-Based Development**: Spec → Design → Implementation → Testing → Resolution
51
- - **Agent Coordination**: Seamless handoffs between multiple AI agents
52
- - **Continuous Learning**: Retrospective-driven improvement system
53
-
54
- #### 🔄 Breaking Changes
55
- - **Simplified Labels**: Reduced from 15 to 9 essential labels
56
- - **Install Method**: Single npm install method (removed curl, Python options)
57
- - **Generic Examples**: All Ashley-specific examples replaced with universal patterns
58
-
59
- #### 🐛 Bug Fixes
60
- - **TypeScript Compilation**: Fixed all compilation issues
61
- - **Import Dependencies**: Resolved missing dependencies
62
- - **Test Utilities**: Made generic and framework-agnostic
63
- - **Repository References**: Updated all URLs to point to FRAIM repository
64
-
65
- #### 📦 Dependencies
66
- - Added TypeScript support with proper type definitions
67
- - Added tsx for TypeScript execution
68
- - Added dotenv for environment management
69
- - Updated Node.js engine requirement to >=16.0.0
70
-
71
- ---
72
-
73
- ## [1.0.12] - Previous Release
74
- - Initial FRAIM framework with Ashley-specific implementations
75
- - Basic rule system and workflows
76
- - GitHub integration and automation