fraim-framework 2.0.167 → 2.0.168
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.
- package/dist/src/ai-hub/catalog.js +28 -14
- package/dist/src/ai-hub/server.js +10 -403
- package/dist/src/cli/commands/init-project.js +1 -98
- package/dist/src/cli/commands/manager.js +40 -0
- package/dist/src/cli/commands/sync.js +17 -21
- package/dist/src/cli/fraim.js +2 -0
- package/dist/src/cli/utils/github-workflow-sync.js +12 -146
- package/dist/src/cli/utils/manager-pack-sync.js +188 -0
- package/dist/src/cli/utils/manager-publish.js +76 -0
- package/dist/src/cli/utils/user-config.js +20 -0
- package/dist/src/core/fraim-config-schema.generated.js +85 -10
- package/dist/src/core/manager-pack.js +26 -0
- package/dist/src/first-run/install-state.js +1 -0
- package/dist/src/first-run/server.js +9 -0
- package/dist/src/first-run/session-service.js +117 -23
- package/dist/src/first-run/types.js +2 -5
- package/dist/src/local-mcp-server/learning-context-builder.js +45 -8
- package/dist/src/local-mcp-server/stdio-server.js +28 -0
- package/index.js +1 -1
- package/package.json +1 -2
- package/public/ai-hub/index.html +0 -81
- package/public/ai-hub/powerpoint-taskpane/index.html +236 -236
- package/public/ai-hub/powerpoint-taskpane/manifest.xml +29 -29
- package/public/ai-hub/script.js +3 -219
- package/public/ai-hub/styles.css +8 -36
- package/public/first-run/index.html +1 -1
- package/public/first-run/script.js +459 -530
- package/public/first-run/styles.css +288 -73
- package/public/portfolio/ashley.html +1 -1
- package/public/portfolio/casey.html +1 -1
- package/public/portfolio/celia.html +1 -1
- package/public/portfolio/gautam.html +1 -1
- package/public/portfolio/hari.html +1 -1
- package/public/portfolio/maestro.html +1 -1
- package/public/portfolio/mandy.html +1 -1
- package/public/portfolio/pam.html +6 -6
- package/public/portfolio/qasm.html +1 -1
- package/public/portfolio/sade.html +1 -1
- package/public/portfolio/sam.html +1 -1
- package/public/portfolio/swen.html +6 -6
- package/dist/src/ai-hub/word-sideload.js +0 -95
- package/dist/src/cli/commands/test-mcp.js +0 -171
- package/dist/src/cli/setup/first-run.js +0 -242
- package/dist/src/config/ai-manager-hiring.js +0 -121
- package/dist/src/config/compat.js +0 -16
- package/dist/src/config/feature-flags.js +0 -25
- package/dist/src/config/persona-capability-bundles.js +0 -273
- package/dist/src/config/persona-hiring.js +0 -270
- package/dist/src/config/portfolio-slug-overrides.js +0 -17
- package/dist/src/config/pricing.js +0 -37
- package/dist/src/config/stripe.js +0 -43
- package/dist/src/core/config-writer.js +0 -75
- package/dist/src/core/utils/job-aliases.js +0 -47
- package/dist/src/core/utils/workflow-parser.js +0 -174
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.testMCPCommand = exports.runTestMCP = void 0;
|
|
40
|
-
const commander_1 = require("commander");
|
|
41
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
42
|
-
const fs_1 = __importDefault(require("fs"));
|
|
43
|
-
const path_1 = __importDefault(require("path"));
|
|
44
|
-
const ide_detector_1 = require("../setup/ide-detector");
|
|
45
|
-
const script_sync_utils_1 = require("../utils/script-sync-utils");
|
|
46
|
-
const testIDEConfig = async (ide) => {
|
|
47
|
-
const result = {
|
|
48
|
-
ide: ide.name,
|
|
49
|
-
configExists: false,
|
|
50
|
-
configValid: false,
|
|
51
|
-
mcpServers: [],
|
|
52
|
-
errors: []
|
|
53
|
-
};
|
|
54
|
-
const configPath = (0, ide_detector_1.expandPath)(ide.configPath);
|
|
55
|
-
if (!fs_1.default.existsSync(configPath)) {
|
|
56
|
-
result.errors.push('Config file does not exist');
|
|
57
|
-
return result;
|
|
58
|
-
}
|
|
59
|
-
result.configExists = true;
|
|
60
|
-
try {
|
|
61
|
-
if (ide.configFormat === 'json') {
|
|
62
|
-
const configContent = fs_1.default.readFileSync(configPath, 'utf8');
|
|
63
|
-
const config = JSON.parse(configContent);
|
|
64
|
-
const servers = ide.configType === 'vscode' ? config.servers : config.mcpServers;
|
|
65
|
-
if (servers) {
|
|
66
|
-
result.configValid = true;
|
|
67
|
-
result.mcpServers = Object.keys(servers);
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
const expectedKey = ide.configType === 'vscode' ? 'servers' : 'mcpServers';
|
|
71
|
-
result.errors.push(`No ${expectedKey} section found`);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
else if (ide.configFormat === 'toml') {
|
|
75
|
-
const configContent = fs_1.default.readFileSync(configPath, 'utf8');
|
|
76
|
-
// Simple TOML parsing for MCP servers
|
|
77
|
-
const serverMatches = configContent.match(/\[mcp_servers\.(\w+)\]/g);
|
|
78
|
-
if (serverMatches) {
|
|
79
|
-
result.configValid = true;
|
|
80
|
-
result.mcpServers = serverMatches.map(match => match.replace(/\[mcp_servers\.(\w+)\]/, '$1'));
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
result.errors.push('No mcp_servers sections found');
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
catch (error) {
|
|
88
|
-
result.errors.push(`Failed to parse config: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
89
|
-
}
|
|
90
|
-
return result;
|
|
91
|
-
};
|
|
92
|
-
const checkGlobalSetup = () => {
|
|
93
|
-
const globalConfigPath = path_1.default.join((0, script_sync_utils_1.getUserFraimDir)(), 'config.json');
|
|
94
|
-
return fs_1.default.existsSync(globalConfigPath);
|
|
95
|
-
};
|
|
96
|
-
const runTestMCP = async () => {
|
|
97
|
-
console.log(chalk_1.default.blue('🔍 Testing MCP configuration...\n'));
|
|
98
|
-
// Check global setup
|
|
99
|
-
if (!checkGlobalSetup()) {
|
|
100
|
-
console.log(chalk_1.default.red('❌ Global FRAIM setup not found.'));
|
|
101
|
-
console.log(chalk_1.default.yellow('Please run: fraim setup --key=<your-fraim-key>'));
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
console.log(chalk_1.default.green('✅ Global FRAIM setup found'));
|
|
105
|
-
// Detect IDEs
|
|
106
|
-
const detectedIDEs = (0, ide_detector_1.detectInstalledIDEs)();
|
|
107
|
-
if (detectedIDEs.length === 0) {
|
|
108
|
-
console.log(chalk_1.default.yellow('⚠️ No supported IDEs detected.'));
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
console.log(chalk_1.default.blue(`\n🔍 Testing ${detectedIDEs.length} detected IDEs...\n`));
|
|
112
|
-
const results = await Promise.all(detectedIDEs.map(ide => testIDEConfig(ide)));
|
|
113
|
-
let totalConfigured = 0;
|
|
114
|
-
let totalWithFRAIM = 0;
|
|
115
|
-
for (const result of results) {
|
|
116
|
-
console.log(chalk_1.default.white(`📱 ${result.ide}`));
|
|
117
|
-
if (!result.configExists) {
|
|
118
|
-
console.log(chalk_1.default.red(' ❌ No MCP config found'));
|
|
119
|
-
console.log(chalk_1.default.gray(` 💡 Run: fraim setup --ide=${result.ide.toLowerCase()}`));
|
|
120
|
-
}
|
|
121
|
-
else if (!result.configValid) {
|
|
122
|
-
console.log(chalk_1.default.yellow(' ⚠️ Config exists but invalid'));
|
|
123
|
-
result.errors.forEach(error => {
|
|
124
|
-
console.log(chalk_1.default.red(` ❌ ${error}`));
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
else {
|
|
128
|
-
totalConfigured++;
|
|
129
|
-
console.log(chalk_1.default.green(` ✅ MCP config valid (${result.mcpServers.length} servers)`));
|
|
130
|
-
// Check for essential servers
|
|
131
|
-
const { BASE_MCP_SERVERS } = await Promise.resolve().then(() => __importStar(require('../mcp/mcp-server-registry')));
|
|
132
|
-
const essentialServers = BASE_MCP_SERVERS.map(s => s.id); // fraim, git, playwright
|
|
133
|
-
const hasEssential = essentialServers.filter(server => result.mcpServers.includes(server));
|
|
134
|
-
if (hasEssential.includes('fraim')) {
|
|
135
|
-
totalWithFRAIM++;
|
|
136
|
-
console.log(chalk_1.default.green(' ✅ FRAIM server configured'));
|
|
137
|
-
}
|
|
138
|
-
else {
|
|
139
|
-
console.log(chalk_1.default.yellow(' ⚠️ FRAIM server missing'));
|
|
140
|
-
}
|
|
141
|
-
if (hasEssential.length > 1) {
|
|
142
|
-
console.log(chalk_1.default.green(` ✅ ${hasEssential.length - 1} additional servers: ${hasEssential.filter(s => s !== 'fraim').join(', ')}`));
|
|
143
|
-
}
|
|
144
|
-
const missingEssential = essentialServers.filter(server => !result.mcpServers.includes(server));
|
|
145
|
-
if (missingEssential.length > 0) {
|
|
146
|
-
console.log(chalk_1.default.yellow(` ⚠️ Missing servers: ${missingEssential.join(', ')}`));
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
console.log(); // Empty line
|
|
150
|
-
}
|
|
151
|
-
// Summary
|
|
152
|
-
console.log(chalk_1.default.blue('📊 Summary:'));
|
|
153
|
-
console.log(chalk_1.default.green(` ✅ ${totalConfigured}/${detectedIDEs.length} IDEs have valid MCP configs`));
|
|
154
|
-
console.log(chalk_1.default.green(` ✅ ${totalWithFRAIM}/${detectedIDEs.length} IDEs have FRAIM configured`));
|
|
155
|
-
if (totalWithFRAIM === 0) {
|
|
156
|
-
console.log(chalk_1.default.red('\n❌ No IDEs have FRAIM configured!'));
|
|
157
|
-
console.log(chalk_1.default.yellow('💡 Run: fraim setup --key=<your-fraim-key>'));
|
|
158
|
-
}
|
|
159
|
-
else if (totalWithFRAIM < detectedIDEs.length) {
|
|
160
|
-
console.log(chalk_1.default.yellow(`\n⚠️ ${detectedIDEs.length - totalWithFRAIM} IDEs missing FRAIM configuration`));
|
|
161
|
-
console.log(chalk_1.default.yellow('💡 Run: fraim setup to configure remaining IDEs'));
|
|
162
|
-
}
|
|
163
|
-
else {
|
|
164
|
-
console.log(chalk_1.default.green('\n🎉 All detected IDEs have FRAIM configured!'));
|
|
165
|
-
console.log(chalk_1.default.blue('💡 Try running: fraim init-project in any project'));
|
|
166
|
-
}
|
|
167
|
-
};
|
|
168
|
-
exports.runTestMCP = runTestMCP;
|
|
169
|
-
exports.testMCPCommand = new commander_1.Command('test-mcp')
|
|
170
|
-
.description('Test MCP server configurations for all detected IDEs')
|
|
171
|
-
.action(exports.runTestMCP);
|
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.runFirstRunExperience = void 0;
|
|
40
|
-
const prompts_1 = __importDefault(require("prompts"));
|
|
41
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
42
|
-
const fs_1 = __importDefault(require("fs"));
|
|
43
|
-
const path_1 = __importDefault(require("path"));
|
|
44
|
-
const os_1 = __importDefault(require("os"));
|
|
45
|
-
const script_sync_utils_1 = require("../utils/script-sync-utils");
|
|
46
|
-
const project_fraim_paths_1 = require("../../core/utils/project-fraim-paths");
|
|
47
|
-
const loadGlobalConfig = () => {
|
|
48
|
-
const globalConfigPath = path_1.default.join((0, script_sync_utils_1.getUserFraimDir)(), 'config.json');
|
|
49
|
-
if (!fs_1.default.existsSync(globalConfigPath)) {
|
|
50
|
-
return null;
|
|
51
|
-
}
|
|
52
|
-
try {
|
|
53
|
-
const config = JSON.parse(fs_1.default.readFileSync(globalConfigPath, 'utf8'));
|
|
54
|
-
return {
|
|
55
|
-
fraimKey: config.apiKey,
|
|
56
|
-
githubToken: config.githubToken
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
catch (e) {
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
const checkMCPConfigurations = () => {
|
|
64
|
-
const sources = [];
|
|
65
|
-
// Check Kiro MCP config
|
|
66
|
-
const kiroConfigPath = path_1.default.join(os_1.default.homedir(), '.kiro', 'settings', 'mcp.json');
|
|
67
|
-
if (fs_1.default.existsSync(kiroConfigPath)) {
|
|
68
|
-
try {
|
|
69
|
-
const kiroConfig = JSON.parse(fs_1.default.readFileSync(kiroConfigPath, 'utf8'));
|
|
70
|
-
if (kiroConfig.mcpServers?.fraim) {
|
|
71
|
-
sources.push('Kiro');
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
catch (e) {
|
|
75
|
-
// Ignore parsing errors
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
// Check Claude Desktop / Cowork config
|
|
79
|
-
const claudeConfigPath = path_1.default.join(os_1.default.homedir(), 'AppData', 'Roaming', 'Claude', 'claude_desktop_config.json');
|
|
80
|
-
if (fs_1.default.existsSync(claudeConfigPath)) {
|
|
81
|
-
try {
|
|
82
|
-
const claudeConfig = JSON.parse(fs_1.default.readFileSync(claudeConfigPath, 'utf8'));
|
|
83
|
-
if (claudeConfig.mcpServers?.fraim) {
|
|
84
|
-
sources.push('Claude Desktop / Cowork');
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
catch (e) {
|
|
88
|
-
// Ignore parsing errors
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
// Check macOS Claude Desktop / Cowork config path
|
|
92
|
-
const claudeMacPath = path_1.default.join(os_1.default.homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
|
|
93
|
-
if (fs_1.default.existsSync(claudeMacPath)) {
|
|
94
|
-
try {
|
|
95
|
-
const claudeConfig = JSON.parse(fs_1.default.readFileSync(claudeMacPath, 'utf8'));
|
|
96
|
-
if (claudeConfig.mcpServers?.fraim) {
|
|
97
|
-
sources.push('Claude Desktop / Cowork (macOS)');
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
catch (e) {
|
|
101
|
-
// Ignore parsing errors
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
// Check VS Code MCP config (uses "servers" key)
|
|
105
|
-
const vscodePaths = [
|
|
106
|
-
path_1.default.join(os_1.default.homedir(), 'AppData', 'Roaming', 'Code', 'User', 'mcp.json'),
|
|
107
|
-
path_1.default.join(os_1.default.homedir(), 'Library', 'Application Support', 'Code', 'User', 'mcp.json'),
|
|
108
|
-
path_1.default.join(os_1.default.homedir(), '.config', 'Code', 'User', 'mcp.json')
|
|
109
|
-
];
|
|
110
|
-
for (const vscodePath of vscodePaths) {
|
|
111
|
-
if (fs_1.default.existsSync(vscodePath)) {
|
|
112
|
-
try {
|
|
113
|
-
const vscodeConfig = JSON.parse(fs_1.default.readFileSync(vscodePath, 'utf8'));
|
|
114
|
-
if (vscodeConfig.servers?.fraim) {
|
|
115
|
-
sources.push('VSCode');
|
|
116
|
-
break;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
catch (e) {
|
|
120
|
-
// Ignore parsing errors
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
return {
|
|
125
|
-
found: sources.length > 0,
|
|
126
|
-
sources
|
|
127
|
-
};
|
|
128
|
-
};
|
|
129
|
-
const runFirstRunExperience = async () => {
|
|
130
|
-
// Skip interactive setup in CI/Test environments
|
|
131
|
-
if (process.env.CI === 'true' || process.env.TEST_MODE === 'true') {
|
|
132
|
-
console.log(chalk_1.default.yellow('ℹ️ Skipping interactive first-run experience (CI/TEST_MODE detected)'));
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
console.log(chalk_1.default.blue('\n👋 Welcome to FRAIM! Let\'s get you set up.\n'));
|
|
136
|
-
// Check for existing configuration
|
|
137
|
-
const globalConfig = loadGlobalConfig();
|
|
138
|
-
const mcpCheck = checkMCPConfigurations();
|
|
139
|
-
if (globalConfig && globalConfig.fraimKey) {
|
|
140
|
-
console.log(chalk_1.default.green('✅ Found existing FRAIM configuration'));
|
|
141
|
-
if (mcpCheck.found) {
|
|
142
|
-
console.log(chalk_1.default.green(`✅ Found FRAIM MCP configuration in: ${mcpCheck.sources.join(', ')}`));
|
|
143
|
-
console.log(chalk_1.default.blue('🎉 You\'re all set! FRAIM is ready to use.\n'));
|
|
144
|
-
}
|
|
145
|
-
else {
|
|
146
|
-
console.log(chalk_1.default.yellow('⚠️ FRAIM key found but no MCP configuration detected.'));
|
|
147
|
-
console.log(chalk_1.default.cyan('💡 Consider running "fraim add-ide" to configure your IDE.\n'));
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
else if (mcpCheck.found) {
|
|
151
|
-
console.log(chalk_1.default.green(`✅ Found FRAIM MCP configuration in: ${mcpCheck.sources.join(', ')}`));
|
|
152
|
-
console.log(chalk_1.default.yellow('⚠️ But no global FRAIM configuration found.'));
|
|
153
|
-
console.log(chalk_1.default.cyan('💡 Your MCP setup looks good! Skipping key setup.\n'));
|
|
154
|
-
}
|
|
155
|
-
else {
|
|
156
|
-
// No existing configuration found - ask for FRAIM key
|
|
157
|
-
console.log(chalk_1.default.yellow('🔍 No existing FRAIM configuration detected.\n'));
|
|
158
|
-
let response;
|
|
159
|
-
try {
|
|
160
|
-
response = await (0, prompts_1.default)({
|
|
161
|
-
type: 'text',
|
|
162
|
-
name: 'fraimKey',
|
|
163
|
-
message: 'Do you have a FRAIM key? (Input key or press Enter to skip)',
|
|
164
|
-
validate: (value) => true // Optional input
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
catch (e) {
|
|
168
|
-
console.warn(chalk_1.default.yellow('\n⚠️ Interactive prompts experienced an issue. Skipping setup.\n'));
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
if (response.fraimKey && response.fraimKey.trim().length > 0) {
|
|
172
|
-
const key = response.fraimKey.trim();
|
|
173
|
-
console.log(chalk_1.default.green('\n✅ Key received.'));
|
|
174
|
-
console.log(chalk_1.default.yellow('\nPlease add the following to your IDE\'s MCP config (e.g. claude_desktop_config.json):'));
|
|
175
|
-
const mcpConfig = {
|
|
176
|
-
mcpServers: {
|
|
177
|
-
fraim: {
|
|
178
|
-
serverUrl: "https://fraim.wellnessatwork.me",
|
|
179
|
-
headers: {
|
|
180
|
-
"x-api-key": key
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
};
|
|
185
|
-
console.log(chalk_1.default.cyan(JSON.stringify(mcpConfig, null, 2)));
|
|
186
|
-
console.log('\n');
|
|
187
|
-
}
|
|
188
|
-
else {
|
|
189
|
-
console.log(chalk_1.default.yellow('\nℹ️ If you need a key, please email sid.mathur@gmail.com to request one.\n'));
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
// 2. Ask about Architecture Document
|
|
193
|
-
const archResponse = await (0, prompts_1.default)({
|
|
194
|
-
type: 'confirm',
|
|
195
|
-
name: 'hasArchDoc',
|
|
196
|
-
message: 'Do you have an architecture document for this project?',
|
|
197
|
-
initial: false
|
|
198
|
-
});
|
|
199
|
-
if (!archResponse.hasArchDoc) {
|
|
200
|
-
console.log(chalk_1.default.yellow('\n💡 To create an architecture document, please ask your IDE Agent:'));
|
|
201
|
-
console.log(chalk_1.default.cyan(' "Run the bootstrap/create-architecture workflow"'));
|
|
202
|
-
console.log(chalk_1.default.gray(' (This ensures your agent understands your codebase structure)\n'));
|
|
203
|
-
}
|
|
204
|
-
else {
|
|
205
|
-
const pathResponse = await (0, prompts_1.default)({
|
|
206
|
-
type: 'text',
|
|
207
|
-
name: 'archDocPath',
|
|
208
|
-
message: 'Please provide the relative path to your architecture document:',
|
|
209
|
-
initial: 'docs/architecture.md',
|
|
210
|
-
validate: (value) => value.length > 0 ? true : 'Path cannot be empty'
|
|
211
|
-
});
|
|
212
|
-
if (pathResponse.archDocPath) {
|
|
213
|
-
const fs = await Promise.resolve().then(() => __importStar(require('fs')));
|
|
214
|
-
const path = await Promise.resolve().then(() => __importStar(require('path')));
|
|
215
|
-
const resolvedPath = path.resolve(process.cwd(), pathResponse.archDocPath);
|
|
216
|
-
if (fs.existsSync(resolvedPath)) {
|
|
217
|
-
try {
|
|
218
|
-
const configPath = (0, project_fraim_paths_1.getWorkspaceConfigPath)(process.cwd());
|
|
219
|
-
if (fs.existsSync(configPath)) {
|
|
220
|
-
const configContent = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
221
|
-
if (!configContent.customizations)
|
|
222
|
-
configContent.customizations = {};
|
|
223
|
-
configContent.customizations.architectureDoc = pathResponse.archDocPath;
|
|
224
|
-
fs.writeFileSync(configPath, JSON.stringify(configContent, null, 2));
|
|
225
|
-
console.log(chalk_1.default.green(`\n✅ Linked architecture document: ${pathResponse.archDocPath}`));
|
|
226
|
-
}
|
|
227
|
-
else {
|
|
228
|
-
console.log(chalk_1.default.red(`\n❌ ${(0, project_fraim_paths_1.getWorkspaceFraimDisplayPath)('config.json')} not found. Could not save preference.`));
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
catch (e) {
|
|
232
|
-
console.error(chalk_1.default.red('\n❌ Failed to update config:'), e);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
else {
|
|
236
|
-
console.log(chalk_1.default.yellow(`\n⚠️ File not found at ${pathResponse.archDocPath}. We'll skip linking it for now.`));
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
console.log(chalk_1.default.green(`\n✅ Jobs are installed in ${(0, project_fraim_paths_1.getWorkspaceFraimDisplayPath)('ai-employee/jobs')} and ${(0, project_fraim_paths_1.getWorkspaceFraimDisplayPath)('ai-manager/jobs')}.\n`));
|
|
241
|
-
};
|
|
242
|
-
exports.runFirstRunExperience = runFirstRunExperience;
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.HUMAN_MANAGER_PROFILES = exports.AI_MANAGER_QUALITIES = exports.HIRING_SERVICES = void 0;
|
|
4
|
-
exports.getHumanManagerProfile = getHumanManagerProfile;
|
|
5
|
-
exports.buildSearchQuery = buildSearchQuery;
|
|
6
|
-
exports.buildJobDescription = buildJobDescription;
|
|
7
|
-
exports.buildServiceUrl = buildServiceUrl;
|
|
8
|
-
exports.buildManagerHiringCatalog = buildManagerHiringCatalog;
|
|
9
|
-
/**
|
|
10
|
-
* Issue #538 — human-manager hiring engine (app side).
|
|
11
|
-
*
|
|
12
|
-
* Self-contained on purpose: the app (AI Hub UI modal + bootstrap) must resolve this
|
|
13
|
-
* at runtime in every packaging context (dev tsx, compiled dist, packed CLI), so it
|
|
14
|
-
* must NOT import across the app→registry boundary. The `hire-the-right-human-ai-manager`
|
|
15
|
-
* job uses the mirror engine `registry/scripts/ai-manager-hiring.ts` (self-contained +
|
|
16
|
-
* CLI). The two are kept identical by a parity test (tests/isolated/test-538-ai-manager-hiring.ts);
|
|
17
|
-
* that is the DRY contract — one behavior, enforced, with no fragile cross-boundary import.
|
|
18
|
-
*/
|
|
19
|
-
const persona_hiring_1 = require("./persona-hiring");
|
|
20
|
-
exports.HIRING_SERVICES = ['linkedin', 'indeed', 'seekout'];
|
|
21
|
-
/** The qualities of a strong AI manager — embedded in both the query and the JD. */
|
|
22
|
-
exports.AI_MANAGER_QUALITIES = [
|
|
23
|
-
{ title: 'Clear specification & written communication', detail: 'Can brief an AI agent so it executes correctly the first time.' },
|
|
24
|
-
{ title: 'Trust-but-verify judgment', detail: 'Knows when to delegate to the agent and when to review deeply.' },
|
|
25
|
-
{ title: 'Coaching mindset', detail: 'Gives feedback that compounds into reusable rules and learnings.' },
|
|
26
|
-
{ title: 'Outcome ownership & AI fluency', detail: 'Owns results; comfortable directing autonomous agents.' },
|
|
27
|
-
];
|
|
28
|
-
const GENERALIST_PROFILE = {
|
|
29
|
-
humanTitle: 'Manager',
|
|
30
|
-
keywords: ['"Manager"', '"Director"', '"Team Lead"', '"Chief of Staff"'],
|
|
31
|
-
};
|
|
32
|
-
/** Role key -> the human manager best suited to manage that AI employee. Mirror of registry/scripts/ai-manager-hiring.ts. */
|
|
33
|
-
exports.HUMAN_MANAGER_PROFILES = {
|
|
34
|
-
maestro: { humanTitle: 'Co-Founder / General Manager', keywords: ['"Co-Founder"', '"General Manager"', '"Chief of Staff"', '"Founder"'] },
|
|
35
|
-
beza: { humanTitle: 'Head of Strategy', keywords: ['"Head of Strategy"', '"Strategy Director"', '"Chief of Staff"'] },
|
|
36
|
-
pam: { humanTitle: 'Head of Product', keywords: ['"Head of Product"', '"Group Product Manager"', '"Director of Product"'] },
|
|
37
|
-
swen: { humanTitle: 'Engineering Manager', keywords: ['"Engineering Manager"', '"Tech Lead"', '"Staff Software Engineer"'] },
|
|
38
|
-
qasm: { humanTitle: 'QA Manager', keywords: ['"QA Manager"', '"QA Lead"', '"Head of Quality"'] },
|
|
39
|
-
huxley: { humanTitle: 'Design Manager', keywords: ['"Design Manager"', '"Head of Design"', '"Design Lead"'] },
|
|
40
|
-
gautam: { humanTitle: 'Marketing Director', keywords: ['"Head of Growth"', '"Marketing Director"', '"Demand Generation Lead"'] },
|
|
41
|
-
cela: { humanTitle: 'General Counsel', keywords: ['"General Counsel"', '"Head of Legal"', '"Legal Director"'] },
|
|
42
|
-
sekhar: { humanTitle: 'Security Manager', keywords: ['"Security Manager"', '"Head of Security"', '"CISO"'] },
|
|
43
|
-
ashley: { humanTitle: 'Chief of Staff', keywords: ['"Chief of Staff"', '"Executive Operations Manager"', '"Office Manager"'] },
|
|
44
|
-
mandy: { humanTitle: 'Head of Operations', keywords: ['"Head of Operations"', '"Director of Operations"', '"Program Manager"'] },
|
|
45
|
-
ricardo: { humanTitle: 'Recruiting Manager', keywords: ['"Recruiting Manager"', '"Head of Talent"', '"Talent Acquisition Lead"'] },
|
|
46
|
-
hari: { humanTitle: 'HR Manager', keywords: ['"HR Manager"', '"Head of People"', '"HR Business Partner"'] },
|
|
47
|
-
careena: { humanTitle: 'Head of Talent Development', keywords: ['"Head of Talent Development"', '"L&D Manager"', '"Career Coaching Lead"'] },
|
|
48
|
-
sade: { humanTitle: 'Salesforce Manager', keywords: ['"Salesforce Manager"', '"CRM Lead"', '"Salesforce Architect"'] },
|
|
49
|
-
sam: { humanTitle: 'Sales Manager', keywords: ['"Sales Manager"', '"Head of Sales"', '"Director of Sales"'] },
|
|
50
|
-
casey: { humanTitle: 'Customer Success Manager', keywords: ['"Customer Success Manager"', '"Head of Customer Success"', '"Support Manager"'] },
|
|
51
|
-
deidre: { humanTitle: 'Head of DEI', keywords: ['"Head of DEI"', '"Director of Inclusion"', '"DEI Program Manager"'] },
|
|
52
|
-
mona: { humanTitle: 'Finance Manager', keywords: ['"Finance Manager"', '"Head of Finance"', '"Controller"'] },
|
|
53
|
-
sreya: { humanTitle: 'SRE Manager', keywords: ['"SRE Manager"', '"Head of Reliability"', '"Platform Engineering Lead"'] },
|
|
54
|
-
procella: { humanTitle: 'Procurement Manager', keywords: ['"Procurement Manager"', '"Head of Procurement"', '"Sourcing Lead"'] },
|
|
55
|
-
banke: { humanTitle: 'KYC Operations Manager', keywords: ['"KYC Operations Manager"', '"AML Compliance Manager"', '"Banking Compliance Lead"'] },
|
|
56
|
-
auditya: { humanTitle: 'Audit Manager', keywords: ['"Audit Manager"', '"Internal Audit Lead"', '"Compliance Audit Manager"'] },
|
|
57
|
-
};
|
|
58
|
-
function getHumanManagerProfile(roleKey) {
|
|
59
|
-
return exports.HUMAN_MANAGER_PROFILES[roleKey] ?? GENERALIST_PROFILE;
|
|
60
|
-
}
|
|
61
|
-
const AI_MANAGER_QUERY_TERMS = '("AI" OR "LLM" OR "agentic") AND ("coaching" OR "mentoring")';
|
|
62
|
-
function buildSearchQuery(roleKey) {
|
|
63
|
-
const profile = getHumanManagerProfile(roleKey);
|
|
64
|
-
return `${profile.keywords.join(' OR ')} AND ${AI_MANAGER_QUERY_TERMS}`;
|
|
65
|
-
}
|
|
66
|
-
function buildJobDescription(roleKey) {
|
|
67
|
-
const profile = getHumanManagerProfile(roleKey);
|
|
68
|
-
const role = persona_hiring_1.PERSONA_HIRE_CATALOG[roleKey]?.role ?? 'AI Employee';
|
|
69
|
-
return [
|
|
70
|
-
`${profile.humanTitle} — manager for an ${role}`,
|
|
71
|
-
'',
|
|
72
|
-
`You will manage an ${role} (an autonomous AI agent) and the humans around it, owning the outcomes it ships.`,
|
|
73
|
-
'',
|
|
74
|
-
"What you'll do:",
|
|
75
|
-
`- Write crisp specifications and acceptance criteria the ${role} can execute against.`,
|
|
76
|
-
`- Review the agent's output with judgment: know when to trust it and when to dig in.`,
|
|
77
|
-
'- Coach the agent and team so feedback compounds into reusable rules.',
|
|
78
|
-
'- Own delivery outcomes, not activity; prioritize ruthlessly.',
|
|
79
|
-
'',
|
|
80
|
-
'What makes a strong AI manager:',
|
|
81
|
-
...exports.AI_MANAGER_QUALITIES.map((q) => `- ${q.title}: ${q.detail}`),
|
|
82
|
-
].join('\n');
|
|
83
|
-
}
|
|
84
|
-
function buildServiceUrl(service, query, location) {
|
|
85
|
-
const q = encodeURIComponent(query);
|
|
86
|
-
const loc = location && location.trim().length > 0 ? location.trim() : '';
|
|
87
|
-
switch (service) {
|
|
88
|
-
case 'linkedin':
|
|
89
|
-
return `https://www.linkedin.com/search/results/people/?keywords=${q}`;
|
|
90
|
-
case 'indeed':
|
|
91
|
-
return `https://www.indeed.com/jobs?q=${q}${loc ? `&l=${encodeURIComponent(loc)}` : ''}`;
|
|
92
|
-
case 'seekout':
|
|
93
|
-
return 'https://app.seekout.com/';
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Catalog projection for the AI Hub bootstrap so the client renders off the server's
|
|
98
|
-
* source of truth. Defaults to exactly the hireable personas in `PERSONA_HIRE_CATALOG`.
|
|
99
|
-
*/
|
|
100
|
-
function buildManagerHiringCatalog(roleKeys = Object.keys(persona_hiring_1.PERSONA_HIRE_CATALOG)) {
|
|
101
|
-
const roles = {};
|
|
102
|
-
for (const key of roleKeys) {
|
|
103
|
-
const profile = getHumanManagerProfile(key);
|
|
104
|
-
const query = buildSearchQuery(key);
|
|
105
|
-
// managedRole is derived from PERSONA_HIRE_CATALOG so the bootstrap response
|
|
106
|
-
// shape is unchanged even after removing the field from HumanManagerProfile.
|
|
107
|
-
const managedRole = persona_hiring_1.PERSONA_HIRE_CATALOG[key]?.role ?? 'AI Employee';
|
|
108
|
-
roles[key] = {
|
|
109
|
-
...profile,
|
|
110
|
-
managedRole,
|
|
111
|
-
query,
|
|
112
|
-
jobDescription: buildJobDescription(key),
|
|
113
|
-
serviceUrls: {
|
|
114
|
-
linkedin: buildServiceUrl('linkedin', query),
|
|
115
|
-
indeed: buildServiceUrl('indeed', query),
|
|
116
|
-
seekout: buildServiceUrl('seekout', query),
|
|
117
|
-
},
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
return { qualities: exports.AI_MANAGER_QUALITIES, services: exports.HIRING_SERVICES, roles };
|
|
121
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Compatibility configuration for FRAIM.
|
|
4
|
-
* This file defines breaking changes and minimum required versions for clients.
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.getBreakingChangesNotice = exports.MINIMUM_CLIENT_VERSION = void 0;
|
|
8
|
-
exports.MINIMUM_CLIENT_VERSION = '2.0.94';
|
|
9
|
-
/**
|
|
10
|
-
* Notice template for clients running outdated versions.
|
|
11
|
-
* This is appended to tool responses to guide users toward the standardized setup.
|
|
12
|
-
*/
|
|
13
|
-
const getBreakingChangesNotice = (currentVersion) => {
|
|
14
|
-
return `\n\n---\n\n> [!WARNING] migration_notice\n> **Action Required**: You are using an outdated FRAIM configuration (v${currentVersion}). FRAIM requires at least v${exports.MINIMUM_CLIENT_VERSION}.\n> \n> To fix this permanently so you never have to update again, please run this terminal command **once**:\n> \`\`\`bash\n> npx fraim@latest setup\n> \`\`\`\n> Then restart your IDE.`;
|
|
15
|
-
};
|
|
16
|
-
exports.getBreakingChangesNotice = getBreakingChangesNotice;
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getFeatureFlags = getFeatureFlags;
|
|
4
|
-
exports.isPersonaEntitlementsEnabled = isPersonaEntitlementsEnabled;
|
|
5
|
-
exports.getPublicFeatureFlags = getPublicFeatureFlags;
|
|
6
|
-
function parseBooleanFlag(value) {
|
|
7
|
-
if (!value)
|
|
8
|
-
return false;
|
|
9
|
-
return ['1', 'true', 'yes', 'on'].includes(value.trim().toLowerCase());
|
|
10
|
-
}
|
|
11
|
-
function getFeatureFlags() {
|
|
12
|
-
return {
|
|
13
|
-
personaEntitlements: {
|
|
14
|
-
enabled: parseBooleanFlag(process.env.FRAIM_FF_PERSONA_ENTITLEMENTS)
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
function isPersonaEntitlementsEnabled() {
|
|
19
|
-
return getFeatureFlags().personaEntitlements.enabled;
|
|
20
|
-
}
|
|
21
|
-
function getPublicFeatureFlags() {
|
|
22
|
-
return {
|
|
23
|
-
personaEntitlementsEnabled: isPersonaEntitlementsEnabled()
|
|
24
|
-
};
|
|
25
|
-
}
|