fraim-framework 2.0.76 → 2.0.77

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.
@@ -24,42 +24,38 @@ const checkGlobalSetup = () => {
24
24
  const config = JSON.parse(fs_1.default.readFileSync(globalConfigPath, 'utf8'));
25
25
  return {
26
26
  exists: true,
27
- mode: config.mode || 'integrated', // Default to integrated for backward compatibility
27
+ mode: config.mode || 'integrated',
28
28
  tokens: config.tokens || {}
29
29
  };
30
30
  }
31
- catch (e) {
31
+ catch {
32
32
  return { exists: true, mode: 'integrated', tokens: {} };
33
33
  }
34
34
  };
35
35
  const runInitProject = async () => {
36
- console.log(chalk_1.default.blue('šŸš€ Initializing FRAIM project...'));
37
- // Check if global setup exists
36
+ console.log(chalk_1.default.blue('Initializing FRAIM project...'));
38
37
  const globalSetup = checkGlobalSetup();
39
38
  if (!globalSetup.exists) {
40
- console.log(chalk_1.default.red('āŒ Global FRAIM setup not found.'));
39
+ console.log(chalk_1.default.red('Global FRAIM setup not found.'));
41
40
  console.log(chalk_1.default.yellow('Please run global setup first:'));
42
41
  console.log(chalk_1.default.cyan(' fraim setup'));
43
42
  process.exit(1);
44
43
  }
45
- const mode = globalSetup.mode;
46
- const tokens = globalSetup.tokens || {};
47
- console.log(chalk_1.default.gray(` Mode: ${mode === 'conversational' ? 'Conversational' : 'Integrated'} (from global config)`));
48
44
  const projectRoot = process.cwd();
49
45
  const fraimDir = path_1.default.join(projectRoot, '.fraim');
50
46
  const configPath = path_1.default.join(fraimDir, 'config.json');
51
47
  if (!fs_1.default.existsSync(fraimDir)) {
52
48
  fs_1.default.mkdirSync(fraimDir, { recursive: true });
53
- console.log(chalk_1.default.green('āœ… Created .fraim directory'));
49
+ console.log(chalk_1.default.green('Created .fraim directory'));
54
50
  }
55
51
  else {
56
- console.log(chalk_1.default.yellow('ā„¹ļø .fraim directory already exists'));
52
+ console.log(chalk_1.default.yellow('.fraim directory already exists'));
57
53
  }
58
54
  if (!fs_1.default.existsSync(configPath)) {
55
+ const projectName = path_1.default.basename(projectRoot);
56
+ const preferredMode = globalSetup.mode || 'integrated';
59
57
  let config;
60
- if (mode === 'conversational') {
61
- // Conversational mode - no platform integration
62
- const projectName = path_1.default.basename(projectRoot);
58
+ if (preferredMode === 'conversational') {
63
59
  config = {
64
60
  version: (0, version_utils_1.getFraimVersion)(),
65
61
  project: {
@@ -67,77 +63,72 @@ const runInitProject = async () => {
67
63
  },
68
64
  customizations: {}
69
65
  };
70
- console.log(chalk_1.default.blue(' Conversational mode: No platform integration'));
66
+ console.log(chalk_1.default.blue(' conversational mode: no platform integration'));
71
67
  console.log(chalk_1.default.gray(` Project: ${projectName}`));
72
68
  }
73
69
  else {
74
- // Integrated mode - try to detect platform
75
70
  const detection = (0, platform_detection_1.detectPlatformFromGit)();
76
71
  if (detection.provider !== 'unknown' && detection.repository) {
77
- // Check if we have the appropriate token
78
- const hasToken = detection.provider === 'github' ? tokens.github : tokens.ado;
79
- if (!hasToken) {
80
- console.log(chalk_1.default.yellow(`\nāš ļø Warning: ${detection.provider.toUpperCase()} repository detected but no token configured`));
81
- console.log(chalk_1.default.gray(` Platform features will be limited.`));
82
- console.log(chalk_1.default.cyan(` Run: fraim setup --${detection.provider === 'github' ? 'github' : 'ado'}\n`));
83
- }
84
- // Use detected repository info
72
+ const issueTracking = detection.provider === 'github'
73
+ ? {
74
+ provider: 'github',
75
+ owner: detection.repository.owner,
76
+ name: detection.repository.name
77
+ }
78
+ : {
79
+ provider: 'ado',
80
+ organization: detection.repository.organization,
81
+ project: detection.repository.project,
82
+ name: detection.repository.name
83
+ };
85
84
  config = {
86
85
  version: (0, version_utils_1.getFraimVersion)(),
87
86
  project: {
88
- name: detection.repository.name
87
+ name: detection.repository.name || projectName
89
88
  },
90
89
  repository: detection.repository,
90
+ issueTracking,
91
91
  customizations: {}
92
92
  };
93
93
  console.log(chalk_1.default.blue(` Platform: ${detection.provider.toUpperCase()}`));
94
94
  if (detection.provider === 'github') {
95
95
  console.log(chalk_1.default.gray(` Repository: ${detection.repository.owner}/${detection.repository.name}`));
96
- console.log(chalk_1.default.gray(` Token: ${hasToken ? 'āœ“ Configured' : 'āœ— Missing'}`));
97
96
  }
98
97
  else if (detection.provider === 'ado') {
99
98
  console.log(chalk_1.default.gray(` Organization: ${detection.repository.organization}`));
100
99
  console.log(chalk_1.default.gray(` Project: ${detection.repository.project}`));
101
100
  console.log(chalk_1.default.gray(` Repository: ${detection.repository.name}`));
102
- console.log(chalk_1.default.gray(` Token: ${hasToken ? 'āœ“ Configured' : 'āœ— Missing'}`));
103
101
  }
104
102
  }
105
103
  else {
106
- // No git remote detected - warn user and fallback to conversational-style config
107
- console.log(chalk_1.default.yellow(' āš ļø No git remote detected'));
108
- console.log(chalk_1.default.yellow(' Integrated mode requires a git remote for platform features.'));
109
- console.log(chalk_1.default.gray(' Falling back to conversational mode configuration...'));
110
- const repoName = path_1.default.basename(projectRoot);
111
104
  config = {
112
105
  version: (0, version_utils_1.getFraimVersion)(),
113
106
  project: {
114
- name: repoName
107
+ name: projectName
115
108
  },
116
109
  customizations: {}
117
110
  };
118
- console.log(chalk_1.default.gray(' Please update .fraim/config.json if you add a repository later.'));
111
+ console.log(chalk_1.default.yellow(' No git remote detected. Falling back to conversational mode.'));
119
112
  }
120
113
  }
121
114
  fs_1.default.writeFileSync(configPath, JSON.stringify(config, null, 2));
122
- console.log(chalk_1.default.green('āœ… Created .fraim/config.json'));
115
+ console.log(chalk_1.default.green('Created .fraim/config.json'));
123
116
  }
124
- // Create subdirectories
125
- ['workflows'].forEach(dir => {
117
+ ['workflows'].forEach((dir) => {
126
118
  const dirPath = path_1.default.join(fraimDir, dir);
127
119
  if (!fs_1.default.existsSync(dirPath)) {
128
120
  fs_1.default.mkdirSync(dirPath, { recursive: true });
129
- console.log(chalk_1.default.green(`āœ… Created .fraim/${dir}`));
121
+ console.log(chalk_1.default.green(`Created .fraim/${dir}`));
130
122
  }
131
123
  });
132
- // Sync workflows from registry
133
124
  await (0, sync_1.runSync)({});
134
125
  const codexAvailable = (0, ide_detector_1.detectInstalledIDEs)().some((ide) => ide.configType === 'codex');
135
126
  if (codexAvailable) {
136
127
  const codexLocalResult = (0, codex_local_config_1.ensureCodexLocalConfig)(projectRoot);
137
128
  const status = codexLocalResult.created ? 'Created' : codexLocalResult.updated ? 'Updated' : 'Verified';
138
- console.log(chalk_1.default.green(`āœ… ${status} project Codex config at ${codexLocalResult.path}`));
129
+ console.log(chalk_1.default.green(`${status} project Codex config at ${codexLocalResult.path}`));
139
130
  }
140
- console.log(chalk_1.default.green('\nāœ… FRAIM project initialized!'));
131
+ console.log(chalk_1.default.green('\nFRAIM project initialized!'));
141
132
  console.log(chalk_1.default.cyan('Try: Ask your AI agent "list fraim workflows"'));
142
133
  };
143
134
  exports.runInitProject = runInitProject;
@@ -46,6 +46,9 @@ function loadFraimConfig() {
46
46
  ...(config.customizations || {})
47
47
  }
48
48
  };
49
+ if (config.issueTracking && typeof config.issueTracking === 'object') {
50
+ mergedConfig.issueTracking = config.issueTracking;
51
+ }
49
52
  // Add optional workflow-driven fields only if they exist in the config
50
53
  if (config.compliance) {
51
54
  mergedConfig.compliance = config.compliance;
@@ -106,19 +106,49 @@ class FraimTemplateEngine {
106
106
  return null;
107
107
  }
108
108
  substitutePlatformActions(content) {
109
- const provider = (0, provider_utils_1.detectProvider)(this.repoInfo?.url);
110
- const templates = this.loadProviderTemplates(provider);
111
- if (!templates)
112
- return content;
109
+ const codeProvider = this.getCodeProvider();
110
+ const issueProvider = this.getIssueProvider();
111
+ const codeTemplates = this.loadProviderTemplates(codeProvider);
112
+ const issueTemplates = issueProvider ? this.loadProviderTemplates(issueProvider) : null;
113
113
  let result = content;
114
- for (const [action, template] of Object.entries(templates)) {
115
- const escapedAction = action.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
116
- const regex = new RegExp(`\\{\\{${FraimTemplateEngine.PROXY_ACTION_PREFIX}${escapedAction}\\}\\}`, 'g');
117
- const renderedTemplate = this.renderActionTemplate(template);
118
- result = result.replace(regex, renderedTemplate);
114
+ if (issueTemplates) {
115
+ for (const [action, template] of Object.entries(issueTemplates)) {
116
+ if (!FraimTemplateEngine.ISSUE_ACTIONS.has(action))
117
+ continue;
118
+ const escapedAction = action.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
119
+ const regex = new RegExp(`\\{\\{${FraimTemplateEngine.PROXY_ACTION_PREFIX}${escapedAction}\\}\\}`, 'g');
120
+ result = result.replace(regex, this.renderActionTemplate(template));
121
+ }
122
+ }
123
+ if (codeTemplates) {
124
+ for (const [action, template] of Object.entries(codeTemplates)) {
125
+ if (issueProvider && issueProvider !== codeProvider && FraimTemplateEngine.ISSUE_ACTIONS.has(action))
126
+ continue;
127
+ const escapedAction = action.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
128
+ const regex = new RegExp(`\\{\\{${FraimTemplateEngine.PROXY_ACTION_PREFIX}${escapedAction}\\}\\}`, 'g');
129
+ result = result.replace(regex, this.renderActionTemplate(template));
130
+ }
119
131
  }
120
132
  return result;
121
133
  }
134
+ getCodeProvider() {
135
+ const repoProvider = this.repoInfo?.provider || this.config?.repository?.provider;
136
+ if (typeof repoProvider === 'string' && repoProvider.trim().length > 0) {
137
+ return repoProvider;
138
+ }
139
+ return (0, provider_utils_1.detectProvider)(this.repoInfo?.url || this.config?.repository?.url);
140
+ }
141
+ getIssueProvider() {
142
+ const fromRepoInfo = this.repoInfo?.issueTracking?.provider;
143
+ if (typeof fromRepoInfo === 'string' && fromRepoInfo.trim().length > 0) {
144
+ return fromRepoInfo;
145
+ }
146
+ const fromConfig = this.config?.issueTracking?.provider;
147
+ if (typeof fromConfig === 'string' && fromConfig.trim().length > 0) {
148
+ return fromConfig;
149
+ }
150
+ return null;
151
+ }
122
152
  loadProviderTemplates(provider) {
123
153
  if (this.providerTemplatesCache[provider])
124
154
  return this.providerTemplatesCache[provider];
@@ -130,11 +160,12 @@ class FraimTemplateEngine {
130
160
  return null;
131
161
  }
132
162
  renderActionTemplate(template) {
133
- if (!this.repoInfo && !this.config?.repository) {
163
+ if (!this.repoInfo && !this.config?.repository && !this.config?.issueTracking) {
134
164
  return template;
135
165
  }
136
166
  return template.replace(/\{\{([^}]+)\}\}/g, (match, path) => {
137
167
  const trimmedPath = path.trim();
168
+ // Handle proxy.repository.* variables
138
169
  if (trimmedPath.startsWith('proxy.repository.')) {
139
170
  const repoPath = trimmedPath.substring('proxy.repository.'.length);
140
171
  if (this.repoInfo) {
@@ -148,12 +179,36 @@ class FraimTemplateEngine {
148
179
  return String(value);
149
180
  }
150
181
  }
182
+ // Handle proxy.issueTracking.* variables (for split provider mode)
183
+ if (trimmedPath.startsWith('proxy.issueTracking.')) {
184
+ const issueTrackingPath = trimmedPath.substring('proxy.issueTracking.'.length);
185
+ if (this.repoInfo?.issueTracking) {
186
+ const value = (0, object_utils_1.getNestedValue)(this.repoInfo.issueTracking, issueTrackingPath);
187
+ if (value !== undefined)
188
+ return String(value);
189
+ }
190
+ if (this.config?.issueTracking) {
191
+ const value = (0, object_utils_1.getNestedValue)(this.config.issueTracking, issueTrackingPath);
192
+ if (value !== undefined)
193
+ return String(value);
194
+ }
195
+ }
151
196
  return match;
152
197
  });
153
198
  }
154
199
  }
155
200
  exports.FraimTemplateEngine = FraimTemplateEngine;
156
201
  FraimTemplateEngine.PROXY_ACTION_PREFIX = 'proxy.action.';
202
+ FraimTemplateEngine.ISSUE_ACTIONS = new Set([
203
+ 'get_issue',
204
+ 'update_issue_status',
205
+ 'add_issue_comment',
206
+ 'create_issue',
207
+ 'assign_issue',
208
+ 'search_issues',
209
+ 'close_issue',
210
+ 'list_issues'
211
+ ]);
157
212
  class FraimLocalMCPServer {
158
213
  constructor() {
159
214
  this.config = null;
@@ -365,16 +420,17 @@ class FraimLocalMCPServer {
365
420
  }).trim();
366
421
  }
367
422
  catch (error) {
368
- // If git command fails, construct URL from config if available
369
- if (this.config?.repository?.owner && this.config?.repository?.name) {
370
- const provider = this.config.repository.provider || 'github';
371
- if (provider === 'github') {
372
- repoUrl = `https://github.com/${this.config.repository.owner}/${this.config.repository.name}.git`;
373
- }
374
- else if (provider === 'ado') {
375
- // Azure DevOps URL format
376
- repoUrl = `https://dev.azure.com/${this.config.repository.owner}/${this.config.repository.name}/_git/${this.config.repository.name}`;
377
- }
423
+ // If git command fails, construct URL from config if available.
424
+ const repositoryConfig = this.config?.repository;
425
+ if (repositoryConfig?.provider === 'github' && repositoryConfig.owner && repositoryConfig.name) {
426
+ repoUrl = `https://github.com/${repositoryConfig.owner}/${repositoryConfig.name}.git`;
427
+ this.log(`šŸ“‹ Constructed repo URL from config: ${repoUrl}`);
428
+ }
429
+ else if (repositoryConfig?.provider === 'ado' &&
430
+ repositoryConfig.organization &&
431
+ repositoryConfig.project &&
432
+ repositoryConfig.name) {
433
+ repoUrl = `https://dev.azure.com/${repositoryConfig.organization}/${repositoryConfig.project}/_git/${repositoryConfig.name}`;
378
434
  this.log(`šŸ“‹ Constructed repo URL from config: ${repoUrl}`);
379
435
  }
380
436
  }
@@ -383,10 +439,10 @@ class FraimLocalMCPServer {
383
439
  return null;
384
440
  }
385
441
  // Parse owner and name from URL
386
- let owner = '';
387
442
  let name = '';
388
443
  let organization = '';
389
444
  let project = '';
445
+ let owner = '';
390
446
  // Handle GitHub URLs: https://github.com/owner/repo.git or git@github.com:owner/repo.git
391
447
  const githubHttpsMatch = repoUrl.match(/github\.com[\/:]([^\/]+)\/([^\/\.]+)/);
392
448
  const adoMatch = repoUrl.match(/dev\.azure\.com\/([^\/]+)\/([^\/]+)\/_git\/([^\/]+)/);
@@ -398,7 +454,6 @@ class FraimLocalMCPServer {
398
454
  // Azure DevOps: organization and project are separate fields
399
455
  organization = adoMatch[1];
400
456
  project = adoMatch[2];
401
- owner = organization; // For compatibility
402
457
  name = adoMatch[3];
403
458
  }
404
459
  else if (this.config?.repository) {
@@ -423,15 +478,21 @@ class FraimLocalMCPServer {
423
478
  branch = this.config.repository.defaultBranch;
424
479
  }
425
480
  }
426
- this.repoInfo = {
481
+ const repoInfo = {
427
482
  url: repoUrl,
428
- owner: owner || 'unknown',
429
483
  name: name || 'unknown',
430
484
  ...(organization && { organization }),
431
485
  ...(project && { project }),
432
486
  ...(branch && { branch })
433
487
  };
434
- this.log(`āœ… Detected repo info: ${this.repoInfo.owner}/${this.repoInfo.name}`);
488
+ if (owner) {
489
+ repoInfo.owner = owner;
490
+ }
491
+ this.repoInfo = repoInfo;
492
+ const repoLabel = this.repoInfo.owner
493
+ ? `${this.repoInfo.owner}/${this.repoInfo.name}`
494
+ : this.repoInfo.name;
495
+ this.log(`āœ… Detected repo info: ${repoLabel}`);
435
496
  return this.repoInfo;
436
497
  }
437
498
  catch (error) {
@@ -630,25 +691,57 @@ class FraimLocalMCPServer {
630
691
  if (!hasDirectProviderPlaceholders && !hasDeliveryPlaceholders)
631
692
  return;
632
693
  const engine = this.ensureEngine();
633
- const provider = (0, provider_utils_1.detectProvider)(this.detectRepoInfo()?.url);
634
- if (engine.hasProviderTemplates(provider))
635
- return;
636
- if (engine.loadProviderTemplates(provider))
637
- return;
638
- const filename = `${provider}.json`;
639
- const cached = this.readCachedTemplateFile(filename);
640
- if (cached) {
641
- engine.setProviderTemplates(provider, cached);
642
- return;
694
+ const codeProvider = engine.getCodeProvider();
695
+ const issueProvider = engine.getIssueProvider();
696
+ const providers = Array.from(new Set([codeProvider, issueProvider].filter((provider) => typeof provider === 'string' && provider.length > 0)));
697
+ for (const provider of providers) {
698
+ if (engine.hasProviderTemplates(provider))
699
+ continue;
700
+ if (engine.loadProviderTemplates(provider))
701
+ continue;
702
+ const filename = `${provider}.json`;
703
+ const cached = this.readCachedTemplateFile(filename);
704
+ if (cached) {
705
+ engine.setProviderTemplates(provider, cached);
706
+ continue;
707
+ }
708
+ const remoteContent = await this.fetchRegistryFileFromServer(`providers/${filename}`, requestSessionId);
709
+ if (remoteContent) {
710
+ const parsed = this.parseTemplateJson(remoteContent, `providers/${filename}`);
711
+ if (parsed) {
712
+ engine.setProviderTemplates(provider, parsed);
713
+ this.writeCachedTemplateFile(filename, parsed);
714
+ continue;
715
+ }
716
+ }
717
+ const bundled = this.readBundledTemplateFile(filename);
718
+ if (bundled) {
719
+ engine.setProviderTemplates(provider, bundled);
720
+ }
643
721
  }
644
- const remoteContent = await this.fetchRegistryFileFromServer(`providers/${filename}`, requestSessionId);
645
- if (!remoteContent)
646
- return;
647
- const parsed = this.parseTemplateJson(remoteContent, `providers/${filename}`);
648
- if (!parsed)
649
- return;
650
- engine.setProviderTemplates(provider, parsed);
651
- this.writeCachedTemplateFile(filename, parsed);
722
+ }
723
+ readBundledTemplateFile(filename) {
724
+ const candidates = [
725
+ (0, path_1.join)(__dirname, '..', '..', '..', 'registry', 'providers', filename),
726
+ (0, path_1.join)(__dirname, '..', '..', 'registry', 'providers', filename),
727
+ (0, path_1.join)(process.cwd(), 'registry', 'providers', filename)
728
+ ];
729
+ for (const candidate of candidates) {
730
+ try {
731
+ if (!(0, fs_1.existsSync)(candidate))
732
+ continue;
733
+ const content = (0, fs_1.readFileSync)(candidate, 'utf8');
734
+ const parsed = JSON.parse(content);
735
+ if (parsed && typeof parsed === 'object') {
736
+ this.log(`āœ… Loaded bundled provider template: ${candidate}`);
737
+ return parsed;
738
+ }
739
+ }
740
+ catch (error) {
741
+ this.log(`āš ļø Failed to load bundled template ${candidate}: ${error.message}`);
742
+ }
743
+ }
744
+ return null;
652
745
  }
653
746
  async hydrateTemplateCachesForResponse(response, requestSessionId) {
654
747
  if (!response.result)
@@ -661,10 +754,12 @@ class FraimLocalMCPServer {
661
754
  let processedResponse = this.processResponse(response);
662
755
  // Delivery substitution can introduce provider action placeholders (e.g. {{proxy.action.update_issue_status}})
663
756
  // that were not visible pre-substitution. Run one targeted re-hydration pass if needed.
664
- const provider = (0, provider_utils_1.detectProvider)(this.detectRepoInfo()?.url);
665
757
  const engine = this.ensureEngine();
666
- if (this.responseHasPotentialProviderPlaceholders(processedResponse) &&
667
- !engine.hasProviderTemplates(provider)) {
758
+ const codeProvider = engine.getCodeProvider();
759
+ const issueProvider = engine.getIssueProvider();
760
+ const providers = Array.from(new Set([codeProvider, issueProvider].filter((provider) => typeof provider === 'string' && provider.length > 0)));
761
+ const hasMissingProviderTemplate = providers.some((provider) => !engine.hasProviderTemplates(provider));
762
+ if (this.responseHasPotentialProviderPlaceholders(processedResponse) && hasMissingProviderTemplate) {
668
763
  await this.ensureProviderTemplatesAvailable(processedResponse, requestSessionId);
669
764
  processedResponse = this.processResponse(processedResponse);
670
765
  }
@@ -988,7 +1083,8 @@ class FraimLocalMCPServer {
988
1083
  ...args.repo, // Agent values as fallback
989
1084
  ...detectedRepo // Detected values override (always win)
990
1085
  };
991
- this.log(`[req:${requestId}] Auto-detected and injected repo info: ${args.repo.owner}/${args.repo.name}`);
1086
+ const repoLabel = args.repo.owner ? `${args.repo.owner}/${args.repo.name}` : args.repo.name;
1087
+ this.log(`[req:${requestId}] Auto-detected and injected repo info: ${repoLabel}`);
992
1088
  }
993
1089
  else {
994
1090
  // If detection fails, use agent-provided values (if any)
@@ -1004,12 +1100,25 @@ class FraimLocalMCPServer {
1004
1100
  }
1005
1101
  };
1006
1102
  }
1007
- this.log(`[req:${requestId}] Using agent-provided repo info: ${args.repo.owner}/${args.repo.name}`);
1103
+ const repoLabel = args.repo.owner ? `${args.repo.owner}/${args.repo.name}` : args.repo.name;
1104
+ this.log(`[req:${requestId}] Using agent-provided repo info: ${repoLabel}`);
1008
1105
  }
1106
+ const configuredIssueTracking = this.config?.issueTracking;
1107
+ if (configuredIssueTracking && typeof configuredIssueTracking === 'object') {
1108
+ args.issueTracking = {
1109
+ ...(args.issueTracking || {}),
1110
+ ...configuredIssueTracking
1111
+ };
1112
+ this.log(`[req:${requestId}] Applied issueTracking context: ${args.issueTracking.provider || 'unknown'}`);
1113
+ }
1114
+ const runtimeRepoContext = {
1115
+ ...args.repo,
1116
+ ...(args.issueTracking ? { issueTracking: args.issueTracking } : {})
1117
+ };
1009
1118
  // Keep proxy runtime repository context in sync with connect payload.
1010
- this.repoInfo = args.repo;
1119
+ this.repoInfo = runtimeRepoContext;
1011
1120
  if (this.engine) {
1012
- this.engine.setRepoInfo(args.repo);
1121
+ this.engine.setRepoInfo(runtimeRepoContext);
1013
1122
  }
1014
1123
  // Update the request with injected info
1015
1124
  request.params.arguments = args;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fraim-framework",
3
- "version": "2.0.76",
3
+ "version": "2.0.77",
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": {