fraim 2.0.161 → 2.0.162

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.
@@ -472,6 +472,33 @@ class FraimLocalMCPServer {
472
472
  }
473
473
  return '';
474
474
  }
475
+ // #533: persist the authenticated user email into ~/.fraim/preferences.json so
476
+ // the AI Hub (a separate process) can resolve personal learnings + show the real
477
+ // profile. Merge-and-write; never throw out of the connect path.
478
+ persistUserEmail(userEmail) {
479
+ try {
480
+ const fs = require('fs');
481
+ const path = require('path');
482
+ const dir = (0, project_fraim_paths_1.getUserFraimDirPath)();
483
+ const prefsPath = path.join(dir, 'preferences.json');
484
+ let prefs = {};
485
+ try {
486
+ prefs = JSON.parse(fs.readFileSync(prefsPath, 'utf8'));
487
+ }
488
+ catch {
489
+ prefs = {};
490
+ }
491
+ if (prefs.userEmail === userEmail)
492
+ return; // already current
493
+ (0, fs_1.mkdirSync)(dir, { recursive: true });
494
+ prefs.userEmail = userEmail;
495
+ (0, fs_1.writeFileSync)(prefsPath, JSON.stringify(prefs, null, 2), 'utf8');
496
+ this.log(`Persisted userEmail to ${prefsPath}`);
497
+ }
498
+ catch (e) {
499
+ this.log(`Could not persist userEmail: ${e instanceof Error ? e.message : String(e)}`);
500
+ }
501
+ }
475
502
  log(message) {
476
503
  // Log to stderr (stdout is reserved for MCP protocol)
477
504
  const key = this.apiKey || 'MISSING_API_KEY';
@@ -1199,6 +1226,11 @@ class FraimLocalMCPServer {
1199
1226
  const userEmail = emailMatch[1].trim();
1200
1227
  this.ensureEngine().setUserEmail(userEmail);
1201
1228
  this.log(`[req:${requestId}] Captured user email for template substitution: ${userEmail}`);
1229
+ // #533: persist the authenticated email locally so the AI Hub (a separate
1230
+ // server that never sees fraim_connect) can resolve personal/manager
1231
+ // learnings and show the real identity in its profile card. Merge into
1232
+ // the existing preferences.json rather than overwriting it.
1233
+ this.persistUserEmail(userEmail);
1202
1234
  // Inject learning context from the local workspace (RFC 177: files live on disk, not server).
1203
1235
  const workspaceRoot = this.findProjectRoot() || process.cwd();
1204
1236
  const learningSection = (0, learning_context_builder_js_1.buildLearningContextSection)(workspaceRoot, userEmail, false);
@@ -1206,6 +1238,11 @@ class FraimLocalMCPServer {
1206
1238
  responseText += learningSection;
1207
1239
  this.log(`[req:${requestId}] Injected learning context for ${userEmail} from ${workspaceRoot}`);
1208
1240
  }
1241
+ const teamContextSection = (0, learning_context_builder_js_1.buildTeamContextSection)(workspaceRoot, false);
1242
+ if (teamContextSection) {
1243
+ responseText += teamContextSection;
1244
+ this.log(`[req:${requestId}] Injected team context from ${workspaceRoot}`);
1245
+ }
1209
1246
  }
1210
1247
  if (this.latestConnectSyncWarning) {
1211
1248
  responseText += `\n\n## Local Catalog\n${this.latestConnectSyncWarning}`;
@@ -1220,9 +1257,10 @@ class FraimLocalMCPServer {
1220
1257
  if (typeof text === 'string' && userEmail) {
1221
1258
  const workspaceRoot = this.findProjectRoot() || process.cwd();
1222
1259
  const learningSection = (0, learning_context_builder_js_1.buildLearningContextSection)(workspaceRoot, userEmail, true);
1223
- if (learningSection) {
1224
- finalizedResponse.result.content[0].text = text + `\n\n---` + learningSection;
1225
- this.log(`[req:${requestId}] Injected job-focus learning context for ${userEmail}`);
1260
+ const teamContextSection = (0, learning_context_builder_js_1.buildTeamContextSection)(workspaceRoot, true);
1261
+ if (learningSection || teamContextSection) {
1262
+ finalizedResponse.result.content[0].text = text + `\n\n---` + learningSection + teamContextSection;
1263
+ this.log(`[req:${requestId}] Injected job-focus learning/team context for ${userEmail}`);
1226
1264
  }
1227
1265
  }
1228
1266
  }
@@ -1942,9 +1980,10 @@ class FraimLocalMCPServer {
1942
1980
  if (userEmail) {
1943
1981
  const workspaceRoot = this.findProjectRoot() || process.cwd();
1944
1982
  const learningSection = (0, learning_context_builder_js_1.buildLearningContextSection)(workspaceRoot, userEmail, true);
1945
- if (learningSection) {
1946
- responseText += `\n\n---` + learningSection;
1947
- this.log(`✅ Injected job-focus learning context for ${userEmail} (local override path)`);
1983
+ const teamContextSection = (0, learning_context_builder_js_1.buildTeamContextSection)(workspaceRoot, true);
1984
+ if (learningSection || teamContextSection) {
1985
+ responseText += `\n\n---` + learningSection + teamContextSection;
1986
+ this.log(`✅ Injected job-focus learning/team context for ${userEmail} (local override path)`);
1948
1987
  }
1949
1988
  }
1950
1989
  return await this.finalizeLocalToolTextResponse(request, requestSessionId, requestId, responseText);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fraim",
3
- "version": "2.0.161",
3
+ "version": "2.0.162",
4
4
  "description": "FRAIM CLI - Framework for Rigor-based AI Management (alias for fraim-framework)",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -9,12 +9,13 @@
9
9
  "scripts": {
10
10
  "dev": "tsx --watch src/fraim-mcp-server.ts > server.log 2>&1",
11
11
  "dev:prod": "npm run build && node dist/src/fraim-mcp-server.js > server.log 2>&1",
12
- "build": "tsx scripts/build-fraim-config-schema-template.ts && npm run typecheck:scripts && tsc && npm run build:stubs && npm run build:fraim-brain && node scripts/copy-registry.js && npm run validate:registry && npm run validate:fraim-pro-assets && npm run validate:employee-catalog && tsx scripts/validate-purity.ts",
12
+ "build": "tsx scripts/build-fraim-config-schema-template.ts && npm run typecheck:scripts && tsc && npm run build:stubs && npm run build:fraim-brain && node scripts/copy-registry.js && npm run validate:registry && npm run validate:fraim-pro-assets && npm run validate:employee-catalog && npm run validate:learning-format-contract && tsx scripts/validate-purity.ts",
13
+ "validate:learning-format-contract": "tsx scripts/validate-learning-format-contract.ts",
13
14
  "build:stubs": "tsx scripts/build-stub-registry.ts",
14
15
  "build:fraim-brain": "node scripts/generate-fraim-brain.js",
15
- "test-all": "npm run test && npm run test:isolated && npm run test:ui",
16
+ "test-all": "npm run test && npm run test:isolated tests/isolated/test-*.ts && npm run test:ui",
16
17
  "test": "node scripts/test-with-server.js",
17
- "test:isolated": "npx tsx --test --test-concurrency=1 --test-reporter=spec tests/isolated/test-*.ts",
18
+ "test:isolated": "npx tsx --test --test-concurrency=1 --test-reporter=spec ",
18
19
  "test:smoke": "node scripts/test-with-server.js --tags=smoke",
19
20
  "test:coverage": "node scripts/test-with-server.js --tags=smoke --coverage",
20
21
  "test:stripe": "node scripts/test-with-server.js tests/test-stripe-payment-complete.ts",