fraim-framework 2.0.63 → 2.0.64

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.
@@ -23,6 +23,7 @@ const fs_1 = require("fs");
23
23
  const path_1 = require("path");
24
24
  const os_1 = require("os");
25
25
  const child_process_1 = require("child_process");
26
+ const crypto_1 = require("crypto");
26
27
  const axios_1 = __importDefault(require("axios"));
27
28
  class FraimLocalMCPServer {
28
29
  constructor() {
@@ -34,6 +35,7 @@ class FraimLocalMCPServer {
34
35
  this.repoInfo = null;
35
36
  this.remoteUrl = process.env.FRAIM_REMOTE_URL || 'https://fraim.wellnessatwork.me';
36
37
  this.apiKey = process.env.FRAIM_API_KEY || '';
38
+ this.localVersion = this.detectLocalVersion();
37
39
  if (!this.apiKey) {
38
40
  this.logError('❌ FRAIM_API_KEY environment variable is required');
39
41
  process.exit(1);
@@ -41,13 +43,36 @@ class FraimLocalMCPServer {
41
43
  this.log('🚀 FRAIM Local MCP Server starting...');
42
44
  this.log(`📡 Remote server: ${this.remoteUrl}`);
43
45
  this.log(`🔑 API key: ${this.apiKey.substring(0, 10)}...`);
46
+ this.log(`Local MCP version: ${this.localVersion}`);
44
47
  }
45
48
  log(message) {
46
49
  // Log to stderr (stdout is reserved for MCP protocol)
47
- console.error(`[FRAIM] ${message}`);
50
+ const key = this.apiKey || 'MISSING_API_KEY';
51
+ console.error(`[FRAIM key:${key}] ${message}`);
48
52
  }
49
53
  logError(message) {
50
- console.error(`[FRAIM ERROR] ${message}`);
54
+ const key = this.apiKey || 'MISSING_API_KEY';
55
+ console.error(`[FRAIM ERROR key:${key}] ${message}`);
56
+ }
57
+ detectLocalVersion() {
58
+ const candidates = [
59
+ (0, path_1.join)(__dirname, '..', '..', '..', 'package.json'),
60
+ (0, path_1.join)(__dirname, '..', '..', 'package.json')
61
+ ];
62
+ for (const pkgPath of candidates) {
63
+ try {
64
+ if (!(0, fs_1.existsSync)(pkgPath))
65
+ continue;
66
+ const pkg = JSON.parse((0, fs_1.readFileSync)(pkgPath, 'utf8'));
67
+ if (typeof pkg.version === 'string' && pkg.version.trim().length > 0) {
68
+ return pkg.version;
69
+ }
70
+ }
71
+ catch {
72
+ // Ignore and try the next candidate
73
+ }
74
+ }
75
+ return 'unknown';
51
76
  }
52
77
  findProjectRoot() {
53
78
  // If we already have workspace root from MCP roots, use it
@@ -475,30 +500,31 @@ class FraimLocalMCPServer {
475
500
  * Proxy request to remote FRAIM server
476
501
  */
477
502
  async proxyToRemote(request) {
503
+ const requestId = (0, crypto_1.randomUUID)();
478
504
  try {
479
505
  // Special handling for fraim_connect - automatically inject machine and repo info
480
506
  if (request.method === 'tools/call' && request.params?.name === 'fraim_connect') {
481
- this.log('🔧 Intercepting fraim_connect to inject machine/repo info');
507
+ this.log(`[req:${requestId}] Intercepting fraim_connect to inject machine/repo info`);
482
508
  const args = request.params.arguments || {};
483
509
  // REQUIRED: Auto-detect and inject machine info
484
510
  const detectedMachine = this.detectMachineInfo();
485
511
  args.machine = {
486
- ...detectedMachine,
487
- ...args.machine // Allow agent to override specific fields if needed
512
+ ...args.machine, // Agent values as fallback
513
+ ...detectedMachine // Detected values override (always win)
488
514
  };
489
- this.log(`✅ Injected machine info: ${args.machine.hostname} (${args.machine.platform})`);
515
+ this.log(`[req:${requestId}] Auto-detected and injected machine info: ${args.machine.hostname} (${args.machine.platform}), ${Math.round(args.machine.memory / 1024 / 1024 / 1024)}GB RAM, ${args.machine.cpus} CPUs`);
490
516
  // REQUIRED: Auto-detect and inject repo info
491
517
  const detectedRepo = this.detectRepoInfo();
492
518
  if (detectedRepo) {
493
519
  args.repo = {
494
- ...detectedRepo,
495
- ...args.repo // Allow agent to override specific fields if needed
520
+ ...args.repo, // Agent values as fallback
521
+ ...detectedRepo // Detected values override (always win)
496
522
  };
497
- this.log(`✅ Injected repo info: ${args.repo.owner}/${args.repo.name}`);
523
+ this.log(`[req:${requestId}] Auto-detected and injected repo info: ${args.repo.owner}/${args.repo.name}`);
498
524
  }
499
525
  else {
500
526
  // If detection fails completely, return error instead of sending garbage
501
- this.logError('⚠️ Could not detect repo info and no config available');
527
+ this.logError(`[req:${requestId}] Could not detect repo info and no config available`);
502
528
  return {
503
529
  jsonrpc: '2.0',
504
530
  id: request.id,
@@ -511,23 +537,53 @@ class FraimLocalMCPServer {
511
537
  // Update the request with injected info
512
538
  request.params.arguments = args;
513
539
  }
540
+ this.log(`[req:${requestId}] Proxying ${request.method} to ${this.remoteUrl}/mcp`);
514
541
  const response = await axios_1.default.post(`${this.remoteUrl}/mcp`, request, {
515
542
  headers: {
516
543
  'Content-Type': 'application/json',
517
- 'x-api-key': this.apiKey
544
+ 'x-api-key': this.apiKey,
545
+ 'x-fraim-request-id': requestId,
546
+ 'x-fraim-local-version': this.localVersion
518
547
  },
519
548
  timeout: 30000
520
549
  });
521
550
  return response.data;
522
551
  }
523
552
  catch (error) {
524
- this.logError(`Remote request failed: ${error.message}`);
553
+ const status = error?.response?.status;
554
+ const remoteData = error?.response?.data;
555
+ this.logError(`[req:${requestId}] Remote request failed (${status || 'no-status'}): ${error.message}`);
556
+ if (remoteData && typeof remoteData === 'object') {
557
+ const forwarded = {
558
+ jsonrpc: typeof remoteData.jsonrpc === 'string' ? remoteData.jsonrpc : '2.0',
559
+ id: remoteData.id ?? request.id,
560
+ error: remoteData.error ?? {
561
+ code: -32603,
562
+ message: `Remote server error (${status || 'unknown status'}): ${error.message}`
563
+ }
564
+ };
565
+ if (forwarded.error && typeof forwarded.error === 'object') {
566
+ const existingData = forwarded.error.data;
567
+ forwarded.error.data = {
568
+ ...(existingData && typeof existingData === 'object' ? existingData : {}),
569
+ fraimRequestId: requestId,
570
+ remoteStatus: status ?? null,
571
+ localMcpVersion: this.localVersion
572
+ };
573
+ }
574
+ return forwarded;
575
+ }
525
576
  return {
526
577
  jsonrpc: '2.0',
527
578
  id: request.id,
528
579
  error: {
529
580
  code: -32603,
530
- message: `Remote server error: ${error.message}`
581
+ message: `Remote server error: ${error.message}`,
582
+ data: {
583
+ fraimRequestId: requestId,
584
+ remoteStatus: status ?? null,
585
+ localMcpVersion: this.localVersion
586
+ }
531
587
  }
532
588
  };
533
589
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fraim-framework",
3
- "version": "2.0.63",
3
+ "version": "2.0.64",
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": {
@@ -15,7 +15,7 @@
15
15
  "start:fraim": "tsx src/fraim-mcp-server.ts",
16
16
  "dev:fraim": "tsx --watch src/fraim-mcp-server.ts",
17
17
  "serve:website": "node fraim-pro/serve.js",
18
- "watch:fraimlogs": "tsx scripts/watch-fraim-logs.ts",
18
+ "watch:fraimlogs": "tsx scripts/watch-fraim-logs.ts > prodlogs.log 2>&1",
19
19
  "manage-keys": "tsx scripts/fraim/manage-keys.ts",
20
20
  "view-signups": "tsx scripts/view-signups.ts",
21
21
  "fraim:init": "npm run build && node index.js init",
@@ -0,0 +1,11 @@
1
+ # FRAIM Workflow: cost-optimization
2
+
3
+ > [!IMPORTANT]
4
+ > This is a **FRAIM-managed workflow stub**.
5
+ > To load the full context (rules, templates, and execution steps), ask your AI agent to:
6
+ > `@fraim get_fraim_workflow("cost-optimization")`
7
+ >
8
+ > DO NOT EXECUTE.
9
+
10
+ ## Intent
11
+ Enable AI agents to systematically analyze Azure subscription costs, identify optimization opportunities, and implement cost-saving measures while maintaining production reliability.