fraim-framework 2.0.62 → 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.
package/bin/fraim-mcp.js CHANGED
@@ -1,14 +1,30 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
  /**
3
- * FRAIM MCP Server Entry Point
3
+ * FRAIM Local MCP Proxy
4
4
  *
5
- * This is called by MCP clients (Cursor, Claude Desktop, Windsurf, Kiro, etc.)
6
- * It starts the local STDIO MCP server that proxies to the remote FRAIM server
7
- * and performs template substitution.
5
+ * This is a thin wrapper that launches the local STDIO MCP server.
6
+ * The actual implementation is in dist/src/local-mcp-server/stdio-server.js
8
7
  */
9
8
 
10
- // Load and start the server
11
- const { FraimLocalMCPServer } = require('../dist/src/local-mcp-server/stdio-server.js');
9
+ const path = require('path');
10
+ const { spawn } = require('child_process');
12
11
 
13
- const server = new FraimLocalMCPServer();
14
- server.start();
12
+ // Path to the actual server implementation
13
+ const serverPath = path.join(__dirname, '..', 'dist', 'src', 'local-mcp-server', 'stdio-server.js');
14
+
15
+ // Spawn the server with all arguments and environment variables
16
+ const server = spawn('node', [serverPath, ...process.argv.slice(2)], {
17
+ stdio: 'inherit',
18
+ env: process.env
19
+ });
20
+
21
+ // Forward exit code
22
+ server.on('exit', (code) => {
23
+ process.exit(code || 0);
24
+ });
25
+
26
+ // Handle errors
27
+ server.on('error', (err) => {
28
+ console.error('Failed to start FRAIM MCP server:', err);
29
+ process.exit(1);
30
+ });
@@ -10,22 +10,38 @@ const path_1 = __importDefault(require("path"));
10
10
  const os_1 = __importDefault(require("os"));
11
11
  const chalk_1 = __importDefault(require("chalk"));
12
12
  const sync_1 = require("./sync");
13
- const types_1 = require("../../fraim/types");
14
- const git_utils_1 = require("../../utils/git-utils");
13
+ const platform_detection_1 = require("../../utils/platform-detection");
15
14
  const version_utils_1 = require("../../utils/version-utils");
16
15
  const checkGlobalSetup = () => {
17
16
  const globalConfigPath = path_1.default.join(os_1.default.homedir(), '.fraim', 'config.json');
18
- return fs_1.default.existsSync(globalConfigPath);
17
+ if (!fs_1.default.existsSync(globalConfigPath)) {
18
+ return { exists: false };
19
+ }
20
+ try {
21
+ const config = JSON.parse(fs_1.default.readFileSync(globalConfigPath, 'utf8'));
22
+ return {
23
+ exists: true,
24
+ mode: config.mode || 'integrated', // Default to integrated for backward compatibility
25
+ tokens: config.tokens || {}
26
+ };
27
+ }
28
+ catch (e) {
29
+ return { exists: true, mode: 'integrated', tokens: {} };
30
+ }
19
31
  };
20
32
  const runInitProject = async () => {
21
33
  console.log(chalk_1.default.blue('šŸš€ Initializing FRAIM project...'));
22
34
  // Check if global setup exists
23
- if (!checkGlobalSetup()) {
35
+ const globalSetup = checkGlobalSetup();
36
+ if (!globalSetup.exists) {
24
37
  console.log(chalk_1.default.red('āŒ Global FRAIM setup not found.'));
25
38
  console.log(chalk_1.default.yellow('Please run global setup first:'));
26
- console.log(chalk_1.default.cyan(' fraim setup --key=<your-fraim-key>'));
39
+ console.log(chalk_1.default.cyan(' fraim setup'));
27
40
  process.exit(1);
28
41
  }
42
+ const mode = globalSetup.mode;
43
+ const tokens = globalSetup.tokens || {};
44
+ console.log(chalk_1.default.gray(` Mode: ${mode === 'conversational' ? 'Conversational' : 'Integrated'} (from global config)`));
29
45
  const projectRoot = process.cwd();
30
46
  const fraimDir = path_1.default.join(projectRoot, '.fraim');
31
47
  const configPath = path_1.default.join(fraimDir, 'config.json');
@@ -37,28 +53,84 @@ const runInitProject = async () => {
37
53
  console.log(chalk_1.default.yellow('ā„¹ļø .fraim directory already exists'));
38
54
  }
39
55
  if (!fs_1.default.existsSync(configPath)) {
40
- const remoteInfo = (0, git_utils_1.getGitRemoteInfo)();
41
- // Git remote is optional for project init
42
- const repoOwner = remoteInfo.owner || 'your-username';
43
- const repoName = remoteInfo.repo || path_1.default.basename(projectRoot);
44
- const repoUrl = remoteInfo.owner && remoteInfo.repo
45
- ? `https://github.com/${remoteInfo.owner}/${remoteInfo.repo}.git`
46
- : `https://github.com/${repoOwner}/${repoName}.git`;
47
- const config = {
48
- ...types_1.DEFAULT_FRAIM_CONFIG,
49
- version: (0, version_utils_1.getFraimVersion)(),
50
- project: {
51
- ...types_1.DEFAULT_FRAIM_CONFIG.project,
52
- name: repoName
53
- },
54
- repository: {
55
- provider: 'github',
56
- owner: repoOwner,
57
- name: repoName,
58
- url: repoUrl,
59
- defaultBranch: remoteInfo.defaultBranch || 'main'
56
+ let config;
57
+ if (mode === 'conversational') {
58
+ // Conversational mode - no platform integration
59
+ const projectName = path_1.default.basename(projectRoot);
60
+ config = {
61
+ version: (0, version_utils_1.getFraimVersion)(),
62
+ project: {
63
+ name: projectName
64
+ },
65
+ mode: 'conversational',
66
+ customizations: {
67
+ workflowsPath: '.fraim/workflows'
68
+ }
69
+ };
70
+ console.log(chalk_1.default.blue(' Conversational mode: No platform integration'));
71
+ console.log(chalk_1.default.gray(` Project: ${projectName}`));
72
+ }
73
+ else {
74
+ // Integrated mode - try to detect platform
75
+ const detection = (0, platform_detection_1.detectPlatformFromGit)();
76
+ 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
85
+ config = {
86
+ version: (0, version_utils_1.getFraimVersion)(),
87
+ project: {
88
+ name: detection.repository.name
89
+ },
90
+ repository: detection.repository,
91
+ mode: 'integrated',
92
+ customizations: {
93
+ workflowsPath: '.fraim/workflows'
94
+ }
95
+ };
96
+ console.log(chalk_1.default.blue(` Detected ${detection.provider.toUpperCase()} repository`));
97
+ if (detection.provider === 'github') {
98
+ console.log(chalk_1.default.gray(` Repository: ${detection.repository.owner}/${detection.repository.name}`));
99
+ console.log(chalk_1.default.gray(` Token: ${hasToken ? 'āœ“ Configured' : 'āœ— Missing'}`));
100
+ }
101
+ else if (detection.provider === 'ado') {
102
+ console.log(chalk_1.default.gray(` Organization: ${detection.repository.organization}`));
103
+ console.log(chalk_1.default.gray(` Project: ${detection.repository.project}`));
104
+ console.log(chalk_1.default.gray(` Repository: ${detection.repository.name}`));
105
+ console.log(chalk_1.default.gray(` Token: ${hasToken ? 'āœ“ Configured' : 'āœ— Missing'}`));
106
+ }
60
107
  }
61
- };
108
+ else {
109
+ // No git remote detected - warn user
110
+ console.log(chalk_1.default.yellow(' āš ļø No git remote detected'));
111
+ console.log(chalk_1.default.yellow(' Integrated mode requires a git remote for platform features.'));
112
+ console.log(chalk_1.default.gray(' Creating config with placeholder values...'));
113
+ const repoName = path_1.default.basename(projectRoot);
114
+ config = {
115
+ version: (0, version_utils_1.getFraimVersion)(),
116
+ project: {
117
+ name: repoName
118
+ },
119
+ repository: {
120
+ provider: 'github',
121
+ owner: 'your-username',
122
+ name: repoName,
123
+ url: `https://github.com/your-username/${repoName}.git`,
124
+ defaultBranch: 'main'
125
+ },
126
+ mode: 'integrated',
127
+ customizations: {
128
+ workflowsPath: '.fraim/workflows'
129
+ }
130
+ };
131
+ console.log(chalk_1.default.gray(' Please update .fraim/config.json with your repository details.'));
132
+ }
133
+ }
62
134
  fs_1.default.writeFileSync(configPath, JSON.stringify(config, null, 2));
63
135
  console.log(chalk_1.default.green('āœ… Created .fraim/config.json'));
64
136
  }
@@ -10,10 +10,10 @@ const path_1 = __importDefault(require("path"));
10
10
  const chalk_1 = __importDefault(require("chalk"));
11
11
  const first_run_1 = require("../setup/first-run");
12
12
  const sync_1 = require("./sync");
13
- const git_utils_1 = require("../../utils/git-utils");
13
+ const platform_detection_1 = require("../../utils/platform-detection");
14
14
  const version_utils_1 = require("../../utils/version-utils");
15
15
  const script_sync_utils_1 = require("../../utils/script-sync-utils");
16
- const runInit = async () => {
16
+ const runInit = async (options = {}) => {
17
17
  const projectRoot = process.cwd();
18
18
  const fraimDir = path_1.default.join(projectRoot, '.fraim');
19
19
  const configPath = path_1.default.join(fraimDir, 'config.json');
@@ -26,28 +26,85 @@ const runInit = async () => {
26
26
  console.log(chalk_1.default.yellow('ā„¹ļø .fraim directory already exists'));
27
27
  }
28
28
  if (!fs_1.default.existsSync(configPath)) {
29
- const remoteInfo = (0, git_utils_1.getGitRemoteInfo)();
30
- if (!remoteInfo.repo) {
31
- console.log(chalk_1.default.red('āŒ Error: No git remote found. FRAIM requires a git repository with remote origin.'));
32
- console.log(chalk_1.default.yellow('šŸ’” Make sure you\'re in a git repository and have set up a remote origin:'));
33
- console.log(chalk_1.default.gray(' git remote add origin <your-repo-url>'));
34
- process.exit(1);
29
+ let config;
30
+ // Try to detect platform from git remote
31
+ const detection = (0, platform_detection_1.detectPlatformFromGit)();
32
+ if (options.skipPlatform || detection.provider === 'unknown' || !detection.repository) {
33
+ // Conversational mode - no platform integration
34
+ if (!options.skipPlatform && (detection.provider === 'unknown' || !detection.repository)) {
35
+ console.log(chalk_1.default.yellow('\nā„¹ļø No git remote found or unsupported platform.'));
36
+ console.log(chalk_1.default.blue(' Initializing in conversational mode (no platform integration).'));
37
+ console.log(chalk_1.default.gray(' You can still use FRAIM workflows and AI features.'));
38
+ console.log(chalk_1.default.gray(' Platform features (issues, PRs) will be unavailable.\n'));
39
+ }
40
+ else {
41
+ console.log(chalk_1.default.blue('\n Initializing in conversational mode (platform integration skipped).\n'));
42
+ }
43
+ // Get project name from directory or git
44
+ let projectName = path_1.default.basename(projectRoot);
45
+ try {
46
+ const { execSync } = require('child_process');
47
+ const gitName = execSync('git config --get remote.origin.url', {
48
+ stdio: 'pipe',
49
+ timeout: 2000
50
+ }).toString().trim();
51
+ const match = gitName.match(/\/([^\/]+?)(\.git)?$/);
52
+ if (match) {
53
+ projectName = match[1];
54
+ }
55
+ }
56
+ catch (e) {
57
+ // Use directory name as fallback
58
+ }
59
+ config = {
60
+ version: (0, version_utils_1.getFraimVersion)(),
61
+ project: {
62
+ name: projectName
63
+ },
64
+ mode: 'conversational',
65
+ customizations: {
66
+ workflowsPath: '.fraim/workflows'
67
+ }
68
+ };
69
+ console.log(chalk_1.default.gray(` Project: ${projectName}`));
70
+ console.log(chalk_1.default.gray(` Mode: Conversational (no platform integration)`));
35
71
  }
36
- const config = {
37
- version: (0, version_utils_1.getFraimVersion)(),
38
- project: {
39
- name: remoteInfo.repo
40
- },
41
- repository: {
42
- provider: 'github',
43
- owner: remoteInfo.owner || 'your-username',
44
- name: remoteInfo.repo,
45
- defaultBranch: remoteInfo.defaultBranch || 'main'
46
- },
47
- customizations: {
48
- workflowsPath: '.fraim/workflows'
72
+ else {
73
+ // Integrated mode - use platform
74
+ if (!detection.repository) {
75
+ console.log(chalk_1.default.red('āŒ Error: Repository information not available'));
76
+ process.exit(1);
49
77
  }
50
- };
78
+ // Validate the detected repository config
79
+ const validation = (0, platform_detection_1.validateRepositoryConfig)(detection.repository);
80
+ if (!validation.valid) {
81
+ console.log(chalk_1.default.red('āŒ Error: Invalid repository configuration:'));
82
+ validation.errors.forEach(err => console.log(chalk_1.default.red(` - ${err}`)));
83
+ process.exit(1);
84
+ }
85
+ console.log(chalk_1.default.blue('\n Initializing in integrated mode (platform integration enabled).'));
86
+ console.log(chalk_1.default.gray(` Platform: ${detection.provider.toUpperCase()}`));
87
+ if (detection.provider === 'github') {
88
+ console.log(chalk_1.default.gray(` Repository: ${detection.repository.owner}/${detection.repository.name}`));
89
+ }
90
+ else if (detection.provider === 'ado') {
91
+ console.log(chalk_1.default.gray(` Organization: ${detection.repository.organization}`));
92
+ console.log(chalk_1.default.gray(` Project: ${detection.repository.project}`));
93
+ console.log(chalk_1.default.gray(` Repository: ${detection.repository.name}`));
94
+ }
95
+ console.log();
96
+ config = {
97
+ version: (0, version_utils_1.getFraimVersion)(),
98
+ project: {
99
+ name: detection.repository.name
100
+ },
101
+ repository: detection.repository,
102
+ mode: 'integrated',
103
+ customizations: {
104
+ workflowsPath: '.fraim/workflows'
105
+ }
106
+ };
107
+ }
51
108
  fs_1.default.writeFileSync(configPath, JSON.stringify(config, null, 2));
52
109
  console.log(chalk_1.default.green('āœ… Created .fraim/config.json'));
53
110
  }
@@ -89,4 +146,5 @@ const runInit = async () => {
89
146
  exports.runInit = runInit;
90
147
  exports.initCommand = new commander_1.Command('init')
91
148
  .description('Initialize FRAIM in the current project')
92
- .action(exports.runInit);
149
+ .option('--skip-platform', 'Skip platform integration (conversational mode only)')
150
+ .action((options) => (0, exports.runInit)(options));