fraim-framework 2.0.77 → 2.0.80
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/README.md +77 -1
- package/bin/fraim-mcp.js +1 -1
- package/bin/fraim.js +1 -1
- package/dist/src/cli/commands/add-ide.js +36 -20
- package/dist/src/cli/commands/init-project.js +17 -6
- package/dist/src/cli/commands/setup.js +407 -21
- package/dist/src/cli/commands/test-mcp.js +2 -2
- package/dist/src/cli/setup/auto-mcp-setup.js +27 -10
- package/dist/src/cli/setup/codex-local-config.js +3 -3
- package/dist/src/cli/setup/first-run.js +2 -1
- package/dist/src/cli/setup/ide-detector.js +1 -1
- package/dist/src/cli/setup/mcp-config-generator.js +206 -49
- package/dist/src/cli/setup/token-validator.js +8 -0
- package/dist/src/cli/utils/platform-detection.js +45 -0
- package/dist/src/core/config-loader.js +1 -1
- package/dist/src/core/utils/provider-utils.js +5 -1
- package/dist/src/local-mcp-server/stdio-server.js +84 -15
- package/index.js +1 -1
- package/package.json +116 -116
- package/dist/src/cli/commands/init.js +0 -148
- package/dist/src/cli/commands/mcp.js +0 -65
- package/dist/src/cli/commands/wizard.js +0 -35
package/README.md
CHANGED
|
@@ -233,6 +233,34 @@ npm install -g fraim-framework
|
|
|
233
233
|
fraim setup # Complete setup with IDE configuration
|
|
234
234
|
```
|
|
235
235
|
|
|
236
|
+
The setup command supports three modes:
|
|
237
|
+
|
|
238
|
+
**Conversational Mode**: AI workflows only, no platform integration required
|
|
239
|
+
```bash
|
|
240
|
+
fraim setup --key=<your-fraim-key>
|
|
241
|
+
# Select "Conversational Mode" when prompted
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**Integrated Mode**: Single platform for both code hosting and issue tracking
|
|
245
|
+
```bash
|
|
246
|
+
fraim setup --key=<your-fraim-key>
|
|
247
|
+
# Select "Integrated Mode" when prompted
|
|
248
|
+
# Choose platform: GitHub, Azure DevOps, or GitLab
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
**Split Mode**: Separate platforms for code hosting and issue tracking
|
|
252
|
+
```bash
|
|
253
|
+
fraim setup --key=<your-fraim-key>
|
|
254
|
+
# Select "Split Mode" when prompted
|
|
255
|
+
# Choose code repository platform: GitHub, Azure DevOps, or GitLab
|
|
256
|
+
# Choose issue tracking platform: GitHub, Azure DevOps, GitLab, or Jira
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Common Split mode combinations:
|
|
260
|
+
- GitHub (code) + Jira (issues)
|
|
261
|
+
- GitLab (code) + Jira (issues)
|
|
262
|
+
- Azure DevOps (code) + GitHub (issues)
|
|
263
|
+
|
|
236
264
|
### **🔧 Additional Commands**
|
|
237
265
|
|
|
238
266
|
After initial setup, you can use these commands:
|
|
@@ -244,6 +272,12 @@ fraim add-ide --ide antigravity # Configure Gemini Antigravity
|
|
|
244
272
|
fraim add-ide --all # Configure all detected IDEs
|
|
245
273
|
fraim add-ide --list # List supported IDEs
|
|
246
274
|
|
|
275
|
+
# Add platform integrations to existing setup
|
|
276
|
+
fraim setup --github # Add GitHub integration
|
|
277
|
+
fraim setup --ado # Add Azure DevOps integration
|
|
278
|
+
fraim setup --gitlab # Add GitLab integration
|
|
279
|
+
fraim setup --jira # Add Jira integration
|
|
280
|
+
|
|
247
281
|
# Project initialization
|
|
248
282
|
fraim init-project # Initialize FRAIM in current project
|
|
249
283
|
|
|
@@ -255,7 +289,49 @@ fraim doctor # Diagnose configuration issues
|
|
|
255
289
|
fraim sync # Sync latest workflows and rules
|
|
256
290
|
```
|
|
257
291
|
|
|
258
|
-
**💡 Pro Tip**: Use `fraim add-ide` when you install a new IDE after initial setup. It reuses your existing FRAIM and
|
|
292
|
+
**💡 Pro Tip**: Use `fraim add-ide` when you install a new IDE after initial setup. It reuses your existing FRAIM and platform tokens, making it much faster than running full setup again.
|
|
293
|
+
|
|
294
|
+
### **🔧 Jira Integration Setup**
|
|
295
|
+
|
|
296
|
+
FRAIM uses the official Model Context Protocol (MCP) server for Jira integration. The setup command automatically configures the correct format.
|
|
297
|
+
|
|
298
|
+
**Jira API Token Requirements**:
|
|
299
|
+
1. Go to https://id.atlassian.com/manage-profile/security/api-tokens
|
|
300
|
+
2. Click "Create API token"
|
|
301
|
+
3. Give it a name (e.g., "FRAIM Integration")
|
|
302
|
+
4. Copy the token (starts with ATATT3...)
|
|
303
|
+
5. Use this token during `fraim setup`
|
|
304
|
+
|
|
305
|
+
**Correct MCP Configuration** (automatically generated):
|
|
306
|
+
```json
|
|
307
|
+
{
|
|
308
|
+
"jira": {
|
|
309
|
+
"command": "npx",
|
|
310
|
+
"args": ["-y", "@modelcontextprotocol/server-jira"],
|
|
311
|
+
"env": {
|
|
312
|
+
"JIRA_API_TOKEN": "your-token-here"
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
**⚠️ Common Issues**:
|
|
319
|
+
- **Old configuration format**: If you see `https://mcp.atlassian.com/v1/sse` in your config, this is incorrect. Run `fraim setup --jira` to update.
|
|
320
|
+
- **Token format**: Jira API tokens typically start with `ATATT3`. If your token doesn't match this format, verify you created an API token (not a personal access token).
|
|
321
|
+
- **First run slow**: The first time `npx` runs the Jira MCP server, it downloads the package. This is normal and only happens once.
|
|
322
|
+
|
|
323
|
+
**Troubleshooting**:
|
|
324
|
+
```bash
|
|
325
|
+
# Test Jira MCP connection
|
|
326
|
+
fraim test-mcp
|
|
327
|
+
|
|
328
|
+
# Reconfigure Jira integration
|
|
329
|
+
fraim setup --jira
|
|
330
|
+
|
|
331
|
+
# Check configuration
|
|
332
|
+
cat ~/.kiro/settings/mcp.json # For Kiro IDE
|
|
333
|
+
cat ~/Library/Application\ Support/Claude/claude_desktop_config.json # For Claude Desktop (macOS)
|
|
334
|
+
```
|
|
259
335
|
|
|
260
336
|
|
|
261
337
|
## 🌟 **Why FRAIM is the Future**
|
package/bin/fraim-mcp.js
CHANGED
package/bin/fraim.js
CHANGED
|
@@ -9,12 +9,12 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
9
9
|
const prompts_1 = __importDefault(require("prompts"));
|
|
10
10
|
const fs_1 = __importDefault(require("fs"));
|
|
11
11
|
const path_1 = __importDefault(require("path"));
|
|
12
|
-
const os_1 = __importDefault(require("os"));
|
|
13
12
|
const ide_detector_1 = require("../setup/ide-detector");
|
|
14
13
|
const mcp_config_generator_1 = require("../setup/mcp-config-generator");
|
|
15
14
|
const codex_local_config_1 = require("../setup/codex-local-config");
|
|
15
|
+
const script_sync_utils_1 = require("../utils/script-sync-utils");
|
|
16
16
|
const loadGlobalConfig = () => {
|
|
17
|
-
const globalConfigPath = path_1.default.join(
|
|
17
|
+
const globalConfigPath = path_1.default.join((0, script_sync_utils_1.getUserFraimDir)(), 'config.json');
|
|
18
18
|
if (!fs_1.default.existsSync(globalConfigPath)) {
|
|
19
19
|
return null;
|
|
20
20
|
}
|
|
@@ -23,7 +23,10 @@ const loadGlobalConfig = () => {
|
|
|
23
23
|
return {
|
|
24
24
|
fraimKey: config.apiKey,
|
|
25
25
|
githubToken: config.tokens?.github || config.githubToken, // Support both old and new format
|
|
26
|
-
|
|
26
|
+
gitlabToken: config.tokens?.gitlab,
|
|
27
|
+
jiraToken: config.tokens?.jira,
|
|
28
|
+
mode: config.mode,
|
|
29
|
+
jiraConfig: config.jiraConfig
|
|
27
30
|
};
|
|
28
31
|
}
|
|
29
32
|
catch (e) {
|
|
@@ -75,7 +78,7 @@ const promptForGitHubToken = async (isConversationalMode = false) => {
|
|
|
75
78
|
return tokenResponse.token;
|
|
76
79
|
};
|
|
77
80
|
const saveGitHubTokenToConfig = (githubToken) => {
|
|
78
|
-
const globalConfigPath = path_1.default.join(
|
|
81
|
+
const globalConfigPath = path_1.default.join((0, script_sync_utils_1.getUserFraimDir)(), 'config.json');
|
|
79
82
|
if (fs_1.default.existsSync(globalConfigPath)) {
|
|
80
83
|
try {
|
|
81
84
|
const config = JSON.parse(fs_1.default.readFileSync(globalConfigPath, 'utf8'));
|
|
@@ -95,7 +98,7 @@ const saveGitHubTokenToConfig = (githubToken) => {
|
|
|
95
98
|
}
|
|
96
99
|
};
|
|
97
100
|
exports.saveGitHubTokenToConfig = saveGitHubTokenToConfig;
|
|
98
|
-
const configureIDEMCP = async (ide, fraimKey,
|
|
101
|
+
const configureIDEMCP = async (ide, fraimKey, tokens, jiraConfig) => {
|
|
99
102
|
const configPath = (0, ide_detector_1.expandPath)(ide.configPath);
|
|
100
103
|
console.log(chalk_1.default.blue(`🔧 Configuring ${ide.name}...`));
|
|
101
104
|
// Create backup if config exists
|
|
@@ -112,10 +115,11 @@ const configureIDEMCP = async (ide, fraimKey, githubToken) => {
|
|
|
112
115
|
}
|
|
113
116
|
let existingConfig = {};
|
|
114
117
|
let existingMCPServers = {};
|
|
118
|
+
const serversKey = ide.configType === 'vscode' ? 'servers' : 'mcpServers';
|
|
115
119
|
if (fs_1.default.existsSync(configPath) && ide.configFormat === 'json') {
|
|
116
120
|
try {
|
|
117
121
|
existingConfig = JSON.parse(fs_1.default.readFileSync(configPath, 'utf8'));
|
|
118
|
-
existingMCPServers = existingConfig
|
|
122
|
+
existingMCPServers = existingConfig[serversKey] || {};
|
|
119
123
|
console.log(chalk_1.default.gray(` 📋 Found existing config with ${Object.keys(existingMCPServers).length} MCP servers`));
|
|
120
124
|
}
|
|
121
125
|
catch (e) {
|
|
@@ -129,8 +133,8 @@ const configureIDEMCP = async (ide, fraimKey, githubToken) => {
|
|
|
129
133
|
existingTomlContent = fs_1.default.readFileSync(configPath, 'utf8');
|
|
130
134
|
console.log(chalk_1.default.gray(` 📋 Found existing TOML config`));
|
|
131
135
|
}
|
|
132
|
-
const newTomlContent = (0, mcp_config_generator_1.generateMCPConfig)(ide.configType, fraimKey,
|
|
133
|
-
const serversToAdd = ['fraim', 'git', 'github', 'playwright'];
|
|
136
|
+
const newTomlContent = (0, mcp_config_generator_1.generateMCPConfig)(ide.configType, fraimKey, tokens, jiraConfig);
|
|
137
|
+
const serversToAdd = ['fraim', 'git', 'github', 'gitlab', 'jira', 'playwright'];
|
|
134
138
|
const mergeResult = (0, mcp_config_generator_1.mergeTomlMCPServers)(existingTomlContent, newTomlContent, serversToAdd);
|
|
135
139
|
fs_1.default.writeFileSync(configPath, mergeResult.content);
|
|
136
140
|
mergeResult.addedServers.forEach(server => {
|
|
@@ -144,9 +148,9 @@ const configureIDEMCP = async (ide, fraimKey, githubToken) => {
|
|
|
144
148
|
});
|
|
145
149
|
}
|
|
146
150
|
else {
|
|
147
|
-
//
|
|
148
|
-
const newConfig = (0, mcp_config_generator_1.generateMCPConfig)(ide.configType, fraimKey,
|
|
149
|
-
const newMCPServers = newConfig.mcpServers || {};
|
|
151
|
+
// For JSON configs - intelligent merging
|
|
152
|
+
const newConfig = (0, mcp_config_generator_1.generateMCPConfig)(ide.configType, fraimKey, tokens, jiraConfig);
|
|
153
|
+
const newMCPServers = newConfig[serversKey] || newConfig.mcpServers || {};
|
|
150
154
|
// Merge MCP servers intelligently
|
|
151
155
|
const mergedMCPServers = { ...existingMCPServers };
|
|
152
156
|
const addedServers = [];
|
|
@@ -164,7 +168,7 @@ const configureIDEMCP = async (ide, fraimKey, githubToken) => {
|
|
|
164
168
|
const mergedConfig = {
|
|
165
169
|
...existingConfig,
|
|
166
170
|
...newConfig,
|
|
167
|
-
|
|
171
|
+
[serversKey]: mergedMCPServers
|
|
168
172
|
};
|
|
169
173
|
// Write updated config
|
|
170
174
|
fs_1.default.writeFileSync(configPath, JSON.stringify(mergedConfig, null, 2));
|
|
@@ -197,7 +201,7 @@ const listSupportedIDEs = () => {
|
|
|
197
201
|
console.log(chalk_1.default.yellow('💡 Use "fraim add-ide --ide <name>" to configure a specific IDE'));
|
|
198
202
|
console.log(chalk_1.default.yellow(' Example: fraim add-ide --ide claude'));
|
|
199
203
|
};
|
|
200
|
-
const promptForIDESelection = async (availableIDEs,
|
|
204
|
+
const promptForIDESelection = async (availableIDEs, tokens) => {
|
|
201
205
|
console.log(chalk_1.default.green(`✅ Found ${availableIDEs.length} IDEs that can be configured:\n`));
|
|
202
206
|
availableIDEs.forEach((ide, index) => {
|
|
203
207
|
const configExists = fs_1.default.existsSync((0, ide_detector_1.expandPath)(ide.configPath));
|
|
@@ -208,10 +212,16 @@ const promptForIDESelection = async (availableIDEs, githubToken) => {
|
|
|
208
212
|
console.log(chalk_1.default.blue('\nFRAIM will add these MCP servers:'));
|
|
209
213
|
console.log(chalk_1.default.gray(' • fraim (workflows and AI management)'));
|
|
210
214
|
console.log(chalk_1.default.gray(' • git (version control integration)'));
|
|
211
|
-
if (
|
|
212
|
-
console.log(chalk_1.default.gray('
|
|
215
|
+
if (tokens?.github) {
|
|
216
|
+
console.log(chalk_1.default.gray(' - github (GitHub API access)'));
|
|
213
217
|
}
|
|
214
|
-
|
|
218
|
+
if (tokens?.gitlab) {
|
|
219
|
+
console.log(chalk_1.default.gray(' - gitlab (GitLab API access)'));
|
|
220
|
+
}
|
|
221
|
+
if (tokens?.jira) {
|
|
222
|
+
console.log(chalk_1.default.gray(' - jira (Jira issue tracking)'));
|
|
223
|
+
}
|
|
224
|
+
console.log(chalk_1.default.gray(' - playwright (browser automation)'));
|
|
215
225
|
const response = await (0, prompts_1.default)({
|
|
216
226
|
type: 'text',
|
|
217
227
|
name: 'selection',
|
|
@@ -250,12 +260,18 @@ const runAddIDE = async (options) => {
|
|
|
250
260
|
process.exit(1);
|
|
251
261
|
}
|
|
252
262
|
let githubToken = globalConfig.githubToken;
|
|
263
|
+
const platformTokens = {
|
|
264
|
+
github: globalConfig.githubToken,
|
|
265
|
+
gitlab: globalConfig.gitlabToken,
|
|
266
|
+
jira: globalConfig.jiraToken
|
|
267
|
+
};
|
|
253
268
|
const isConversationalMode = globalConfig.mode === 'conversational';
|
|
254
|
-
if (!githubToken && !isConversationalMode) {
|
|
269
|
+
if (!githubToken && !platformTokens.gitlab && !platformTokens.jira && !isConversationalMode) {
|
|
255
270
|
console.log(chalk_1.default.yellow('⚠️ No GitHub token found in configuration.'));
|
|
256
271
|
githubToken = await promptForGitHubToken(false);
|
|
257
272
|
if (githubToken) {
|
|
258
273
|
saveGitHubTokenToConfig(githubToken);
|
|
274
|
+
platformTokens.github = githubToken;
|
|
259
275
|
}
|
|
260
276
|
}
|
|
261
277
|
if (isConversationalMode && !githubToken) {
|
|
@@ -295,7 +311,7 @@ const runAddIDE = async (options) => {
|
|
|
295
311
|
}
|
|
296
312
|
else {
|
|
297
313
|
// Interactive selection
|
|
298
|
-
idesToConfigure = await promptForIDESelection(detectedIDEs,
|
|
314
|
+
idesToConfigure = await promptForIDESelection(detectedIDEs, platformTokens);
|
|
299
315
|
}
|
|
300
316
|
if (idesToConfigure.length === 0) {
|
|
301
317
|
console.log(chalk_1.default.yellow('⚠️ No IDEs selected for configuration.'));
|
|
@@ -308,7 +324,7 @@ const runAddIDE = async (options) => {
|
|
|
308
324
|
};
|
|
309
325
|
for (const ide of idesToConfigure) {
|
|
310
326
|
try {
|
|
311
|
-
await configureIDEMCP(ide, globalConfig.fraimKey,
|
|
327
|
+
await configureIDEMCP(ide, globalConfig.fraimKey, platformTokens, globalConfig.jiraConfig);
|
|
312
328
|
results.successful.push(ide.name);
|
|
313
329
|
}
|
|
314
330
|
catch (error) {
|
|
@@ -341,7 +357,7 @@ const runAddIDE = async (options) => {
|
|
|
341
357
|
exports.runAddIDE = runAddIDE;
|
|
342
358
|
exports.addIDECommand = new commander_1.Command('add-ide')
|
|
343
359
|
.description('Add FRAIM configuration to additional IDEs')
|
|
344
|
-
.option('--ide <name>', 'Configure specific IDE (claude, antigravity, kiro, cursor, vscode, codex, windsurf)')
|
|
360
|
+
.option('--ide <name>', 'Configure specific IDE (claude, claude-code, antigravity, kiro, cursor, vscode, codex, windsurf)')
|
|
345
361
|
.option('--all', 'Configure all detected IDEs')
|
|
346
362
|
.option('--list', 'List all supported IDEs and their detection status')
|
|
347
363
|
.action(exports.runAddIDE);
|
|
@@ -75,12 +75,19 @@ const runInitProject = async () => {
|
|
|
75
75
|
owner: detection.repository.owner,
|
|
76
76
|
name: detection.repository.name
|
|
77
77
|
}
|
|
78
|
-
:
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
78
|
+
: detection.provider === 'ado'
|
|
79
|
+
? {
|
|
80
|
+
provider: 'ado',
|
|
81
|
+
organization: detection.repository.organization,
|
|
82
|
+
project: detection.repository.project,
|
|
83
|
+
name: detection.repository.name
|
|
84
|
+
}
|
|
85
|
+
: {
|
|
86
|
+
provider: 'gitlab',
|
|
87
|
+
namespace: detection.repository.namespace,
|
|
88
|
+
name: detection.repository.name,
|
|
89
|
+
projectPath: detection.repository.projectPath
|
|
90
|
+
};
|
|
84
91
|
config = {
|
|
85
92
|
version: (0, version_utils_1.getFraimVersion)(),
|
|
86
93
|
project: {
|
|
@@ -99,6 +106,10 @@ const runInitProject = async () => {
|
|
|
99
106
|
console.log(chalk_1.default.gray(` Project: ${detection.repository.project}`));
|
|
100
107
|
console.log(chalk_1.default.gray(` Repository: ${detection.repository.name}`));
|
|
101
108
|
}
|
|
109
|
+
else if (detection.provider === 'gitlab') {
|
|
110
|
+
console.log(chalk_1.default.gray(` Namespace: ${detection.repository.namespace || '(none)'}`));
|
|
111
|
+
console.log(chalk_1.default.gray(` Repository: ${detection.repository.name}`));
|
|
112
|
+
}
|
|
102
113
|
}
|
|
103
114
|
else {
|
|
104
115
|
config = {
|