fraim-framework 2.0.91 → 2.0.92

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.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  /**
4
4
  * FRAIM Framework CLI Entry Point
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mcpCommand = void 0;
4
+ const commander_1 = require("commander");
5
+ const stdio_server_1 = require("../../local-mcp-server/stdio-server");
6
+ /**
7
+ * mcpCommand - Entry point for starting the local FRAIM MCP server.
8
+ * This integrates the local-mcp-server into the main CLI.
9
+ */
10
+ exports.mcpCommand = new commander_1.Command('mcp')
11
+ .description('Start the local FRAIM MCP server (stdio)')
12
+ .action(() => {
13
+ const server = new stdio_server_1.FraimLocalMCPServer();
14
+ server.start();
15
+ });
@@ -0,0 +1,171 @@
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);
@@ -48,6 +48,7 @@ const add_provider_1 = require("./commands/add-provider");
48
48
  const override_1 = require("./commands/override");
49
49
  const list_overridable_1 = require("./commands/list-overridable");
50
50
  const login_1 = require("./commands/login");
51
+ const mcp_1 = require("./commands/mcp");
51
52
  const fs_1 = __importDefault(require("fs"));
52
53
  const path_1 = __importDefault(require("path"));
53
54
  const program = new commander_1.Command();
@@ -85,6 +86,7 @@ program.addCommand(add_provider_1.addProviderCommand);
85
86
  program.addCommand(override_1.overrideCommand);
86
87
  program.addCommand(list_overridable_1.listOverridableCommand);
87
88
  program.addCommand(login_1.loginCommand);
89
+ program.addCommand(mcp_1.mcpCommand);
88
90
  // Wait for async command initialization before parsing
89
91
  (async () => {
90
92
  // Import the initialization promise from setup command
@@ -36,7 +36,8 @@ exports.BASE_MCP_SERVERS = [
36
36
  name: 'FRAIM',
37
37
  description: 'FRAIM workflow orchestration and mentoring',
38
38
  buildServer: (fraimKey) => ({
39
- command: 'fraim-mcp',
39
+ command: 'npx',
40
+ args: ['-y', 'fraim-framework@latest', 'mcp'],
40
41
  env: {
41
42
  // Include API key for IDE configs (Codex, VSCode, etc.)
42
43
  // The stdio-server will use this if set, otherwise falls back to ~/.fraim/config.json
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DeviceFlowService = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ class DeviceFlowService {
10
+ constructor(config) {
11
+ this.config = config;
12
+ }
13
+ /**
14
+ * Start the Device Flow Login
15
+ */
16
+ async login() {
17
+ console.log(chalk_1.default.blue('\n🔗 Starting Authentication...'));
18
+ try {
19
+ // 1. Request device and user codes
20
+ const deviceCode = await this.requestDeviceCode();
21
+ console.log(chalk_1.default.yellow('\nACTION REQUIRED:'));
22
+ console.log(`1. Go to: ${chalk_1.default.cyan.underline(deviceCode.verification_uri)}`);
23
+ console.log(`2. Enter the code: ${chalk_1.default.bold.green(deviceCode.user_code)}`);
24
+ console.log(chalk_1.default.gray(`\nWaiting for authorization (expires in ${Math.floor(deviceCode.expires_in / 60)} minutes)...`));
25
+ // 2. Poll for the access token
26
+ const token = await this.pollForToken(deviceCode.device_code, deviceCode.interval);
27
+ console.log(chalk_1.default.green('\n✅ Authentication Successful!'));
28
+ return token;
29
+ }
30
+ catch (error) {
31
+ console.error(chalk_1.default.red(`\n❌ Authentication failed: ${error.message}`));
32
+ throw error;
33
+ }
34
+ }
35
+ async requestDeviceCode() {
36
+ const response = await axios_1.default.post(this.config.authUrl, {
37
+ client_id: this.config.clientId,
38
+ scope: this.config.scope
39
+ }, {
40
+ headers: { Accept: 'application/json' }
41
+ });
42
+ return response.data;
43
+ }
44
+ async pollForToken(deviceCode, interval) {
45
+ let currentInterval = interval * 1000;
46
+ return new Promise((resolve, reject) => {
47
+ const poll = async () => {
48
+ try {
49
+ const response = await axios_1.default.post(this.config.tokenUrl, {
50
+ client_id: this.config.clientId,
51
+ device_code: deviceCode,
52
+ grant_type: 'urn:ietf:params:oauth:grant-type:device_code'
53
+ }, {
54
+ headers: { Accept: 'application/json' }
55
+ });
56
+ if (response.data.access_token) {
57
+ resolve(response.data.access_token);
58
+ return;
59
+ }
60
+ if (response.data.error) {
61
+ const error = response.data.error;
62
+ if (error === 'authorization_pending') {
63
+ // Keep polling
64
+ setTimeout(poll, currentInterval);
65
+ }
66
+ else if (error === 'slow_down') {
67
+ currentInterval += 5000;
68
+ setTimeout(poll, currentInterval);
69
+ }
70
+ else {
71
+ reject(new Error(response.data.error_description || error));
72
+ }
73
+ }
74
+ }
75
+ catch (error) {
76
+ reject(error);
77
+ }
78
+ };
79
+ setTimeout(poll, currentInterval);
80
+ });
81
+ }
82
+ }
83
+ exports.DeviceFlowService = DeviceFlowService;
@@ -46,6 +46,11 @@ function loadFraimConfig() {
46
46
  ...(config.customizations || {})
47
47
  }
48
48
  };
49
+ if (config.customizations?.postCleanupHook || config.customizations?.cleanupCommand) {
50
+ if (!mergedConfig.customizations)
51
+ mergedConfig.customizations = {};
52
+ mergedConfig.customizations.postCleanupHook = config.customizations.postCleanupHook || config.customizations.cleanupCommand;
53
+ }
49
54
  if (config.issueTracking && typeof config.issueTracking === 'object') {
50
55
  mergedConfig.issueTracking = config.issueTracking;
51
56
  }
@@ -2,6 +2,8 @@
2
2
  /**
3
3
  * FRAIM Configuration Types
4
4
  * TypeScript types for .fraim/config.json
5
+ *
6
+ * Each field includes rich metadata for agent detection and user interaction
5
7
  */
6
8
  Object.defineProperty(exports, "__esModule", { value: true });
7
9
  exports.DEFAULT_FRAIM_CONFIG = void 0;
@@ -31,7 +31,7 @@ function getPort() {
31
31
  */
32
32
  function determineDatabaseName() {
33
33
  try {
34
- const branchName = process.env.FRAIM_BRANCH || (0, child_process_1.execSync)('git rev-parse --abbrev-ref HEAD').toString().trim();
34
+ const branchName = process.env.FRAIM_BRANCH || process.env.FRAIM_BRANCH_NAME || (0, child_process_1.execSync)('git rev-parse --abbrev-ref HEAD').toString().trim();
35
35
  const issueMatch = branchName.match(/issue-(\d+)/i) || branchName.match(/(\d+)-/);
36
36
  if (issueMatch) {
37
37
  return `fraim_issue_${issueMatch[1]}`;
@@ -1264,6 +1264,8 @@ class FraimLocalMCPServer {
1264
1264
  this.engine.setMachineInfo(this.machineInfo);
1265
1265
  this.engine.setRepoInfo(this.repoInfo);
1266
1266
  }
1267
+ // In a proxy setup, the remote server resolves the API key ID during event upload.
1268
+ // No local resolution needed.
1267
1269
  // Update the request with injected info
1268
1270
  request.params.arguments = args;
1269
1271
  }
@@ -1668,31 +1670,19 @@ class FraimLocalMCPServer {
1668
1670
  this.log('✅ FRAIM Local MCP Server ready');
1669
1671
  }
1670
1672
  /**
1671
- * Upload collected usage data to the remote server
1673
+ * Flush collected usage data to the local database
1672
1674
  */
1673
1675
  async uploadUsageData() {
1674
- const events = this.usageCollector.getEventsForUpload();
1675
- if (events.length === 0) {
1676
- return; // Nothing to upload
1676
+ if (this.usageCollector.getEventCount() === 0) {
1677
+ return; // Nothing to flush
1677
1678
  }
1678
1679
  try {
1679
- const response = await axios_1.default.post(`${this.remoteUrl}/api/analytics/events`, { events }, {
1680
- headers: {
1681
- 'Content-Type': 'application/json',
1682
- 'x-api-key': this.apiKey
1683
- },
1684
- timeout: 10000
1685
- });
1686
- if (response.status === 200) {
1687
- this.log(`📊 Uploaded ${events.length} usage events`);
1688
- }
1689
- else {
1690
- this.log(`⚠️ Usage upload failed: ${response.status}`);
1691
- }
1680
+ const count = this.usageCollector.getEventCount();
1681
+ await this.usageCollector.flush(this.remoteUrl, this.apiKey);
1682
+ this.log(`📊 Flushed ${count} usage events to remote server`);
1692
1683
  }
1693
1684
  catch (error) {
1694
- this.log(`❌ Usage upload error: ${error.message}`);
1695
- // Don't re-queue on failure - keep it simple
1685
+ this.log(`❌ Usage flushing error: ${error.message}`);
1696
1686
  }
1697
1687
  }
1698
1688
  }
@@ -1,6 +1,10 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.UsageCollector = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
4
8
  /**
5
9
  * Usage event collector for local MCP proxy
6
10
  * Collects usage events and batches them for upload
@@ -89,6 +93,35 @@ class UsageCollector {
89
93
  getEventCount() {
90
94
  return this.events.length;
91
95
  }
96
+ /**
97
+ * Flush events to the remote server via API
98
+ */
99
+ async flush(remoteUrl, apiKey) {
100
+ if (this.events.length === 0)
101
+ return;
102
+ const events = [...this.events];
103
+ this.events = [];
104
+ try {
105
+ await axios_1.default.post(`${remoteUrl}/api/analytics/events`, {
106
+ events,
107
+ apiKey
108
+ }, {
109
+ timeout: 5000,
110
+ headers: {
111
+ 'x-api-key': apiKey,
112
+ 'Content-Type': 'application/json'
113
+ }
114
+ });
115
+ // Success - events are already cleared from the queue
116
+ }
117
+ catch (error) {
118
+ const status = error.response?.status;
119
+ const message = error.response?.data?.error || error.message;
120
+ console.error(`❌ Failed to flush usage events (HTTP ${status}): ${message}`);
121
+ // Put events back at the beginning of the queue for next try
122
+ this.events = [...events, ...this.events];
123
+ }
124
+ }
92
125
  /**
93
126
  * Shutdown the collector
94
127
  */
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  /**
4
4
  * FRAIM Framework - Smart Entry Point
package/package.json CHANGED
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "name": "fraim-framework",
3
- "version": "2.0.91",
3
+ "version": "2.0.92",
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": {
7
7
  "fraim": "./index.js",
8
- "fraim-framework": "./index.js",
9
- "fraim-mcp": "./bin/fraim-mcp.js"
8
+ "fraim-framework": "./index.js"
10
9
  },
11
10
  "scripts": {
12
11
  "dev": "tsx --watch src/fraim-mcp-server.ts > server.log 2>&1",
13
12
  "dev:prod": "npm run build && node dist/src/fraim-mcp-server.js > server.log 2>&1",
14
- "build": "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 && tsx scripts/validate-purity.ts",
13
+ "build": "tsc && npm run build:stubs && npm run build:fraim-brain && npm run build:config-schema && node scripts/copy-registry.js && npm run validate:registry && npm run validate:fraim-pro-assets && tsx scripts/validate-purity.ts",
15
14
  "build:stubs": "tsx scripts/build-stub-registry.ts",
16
15
  "build:fraim-brain": "node scripts/generate-fraim-brain.js",
16
+ "build:config-schema": "tsx scripts/generate-config-schema-template.ts",
17
17
  "test-all": "npm run test && npm run test:isolated && npm run test:ui",
18
18
  "test": "node scripts/test-with-server.js",
19
19
  "test:isolated": "npx tsx --test --test-reporter=spec tests/isolated/test-*.ts",
@@ -36,7 +36,7 @@
36
36
  "postinstall": "fraim sync --skip-updates || echo 'FRAIM setup skipped.'",
37
37
  "prepublishOnly": "npm run build",
38
38
  "release": "npm version patch && npm publish",
39
- "validate:registry": "tsx scripts/verify-registry-paths.ts && npm run validate:workflows && npm run validate:skills && npm run validate:platform-agnostic && npm run validate:template-namespaces && npm run validate:config-fallbacks && npm run validate:bootstrap-config-coverage && npm run validate:provider-action-mappings && npm run validate:fidelity && npm run validate:config-tokens && npm run validate:brain-mapping",
39
+ "validate:registry": "tsx scripts/verify-registry-paths.ts && npm run validate:workflows && npm run validate:skills && npm run validate:platform-agnostic && npm run validate:template-namespaces && npm run validate:config-fallbacks && npm run validate:bootstrap-config-coverage && npm run validate:provider-action-mappings && npm run validate:fidelity && npm run validate:config-tokens && npm run validate:brain-mapping && npm run validate:template-syntax",
40
40
  "validate:brain-mapping": "tsx scripts/validate-brain-mapping.ts",
41
41
  "validate:fraim-pro-assets": "tsx scripts/validate-fraim-pro-assets.ts",
42
42
  "validate:workflows": "tsx scripts/validate-workflows.ts",
@@ -47,7 +47,8 @@
47
47
  "validate:bootstrap-config-coverage": "tsx scripts/validate-bootstrap-config-coverage.ts",
48
48
  "validate:provider-action-mappings": "tsx scripts/validate-provider-action-mappings.ts",
49
49
  "validate:fidelity": "tsx scripts/validate-fidelity.ts",
50
- "validate:config-tokens": "tsx scripts/validate-config-tokens.ts"
50
+ "validate:config-tokens": "tsx scripts/validate-config-tokens.ts",
51
+ "validate:template-syntax": "tsx scripts/validate-template-syntax.ts"
51
52
  },
52
53
  "repository": {
53
54
  "type": "git",
@@ -82,10 +83,12 @@
82
83
  },
83
84
  "devDependencies": {
84
85
  "@playwright/test": "^1.58.2",
86
+ "@types/adm-zip": "^0.5.7",
85
87
  "@types/cors": "^2.8.19",
86
88
  "@types/express": "^5.0.6",
87
89
  "@types/node": "^20.0.0",
88
90
  "@types/prompts": "^2.4.9",
91
+ "@types/semver": "^7.7.1",
89
92
  "fast-glob": "^3.3.3",
90
93
  "html-to-docx": "^1.8.0",
91
94
  "markdown-it": "^14.1.1",
@@ -114,6 +117,7 @@
114
117
  "access": "public"
115
118
  },
116
119
  "dependencies": {
120
+ "adm-zip": "^0.5.16",
117
121
  "axios": "^1.7.0",
118
122
  "chalk": "4.1.2",
119
123
  "commander": "^14.0.2",
@@ -124,8 +128,10 @@
124
128
  "node-edge-tts": "^1.2.10",
125
129
  "prompts": "^2.4.2",
126
130
  "resend": "^6.9.3",
131
+ "semver": "^7.7.4",
127
132
  "stripe": "^20.3.1",
128
133
  "toml": "^3.0.0",
129
- "tree-kill": "^1.2.2"
134
+ "tree-kill": "^1.2.2",
135
+ "xml2js": "^0.6.2"
130
136
  }
131
137
  }
package/bin/fraim-mcp.js DELETED
@@ -1,63 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * FRAIM MCP Server - Smart Entry Point
5
- * This file handles both production (dist/) and development (src/) environments.
6
- */
7
-
8
- const path = require('path');
9
- const fs = require('fs');
10
- const { spawn } = require('child_process');
11
-
12
- /**
13
- * Runs the MCP server using either the compiled JS or the source TS via tsx
14
- */
15
- function runMCPServer() {
16
- const distPath = path.join(__dirname, '..', 'dist', 'src', 'local-mcp-server', 'stdio-server.js');
17
- const srcPath = path.join(__dirname, '..', 'src', 'local-mcp-server', 'stdio-server.ts');
18
-
19
- // 1. Check if we have a compiled version (Production / CI)
20
- if (fs.existsSync(distPath)) {
21
- // Use spawn to run the compiled JS so it's treated as the main module
22
- const result = spawn('node', [distPath, ...process.argv.slice(2)], {
23
- stdio: 'inherit',
24
- shell: false,
25
- windowsHide: true
26
- });
27
-
28
- // Forward exit code
29
- result.on('exit', (code) => {
30
- process.exit(code || 0);
31
- });
32
-
33
- return;
34
- }
35
-
36
- // 2. Fallback to source version using tsx (Development)
37
- if (fs.existsSync(srcPath)) {
38
- // Use spawn to run tsx so it handles stdio correctly for MCP
39
- const result = spawn('npx', ['tsx', srcPath, ...process.argv.slice(2)], {
40
- stdio: 'inherit',
41
- shell: true,
42
- windowsHide: true
43
- });
44
-
45
- // Forward exit code
46
- result.on('exit', (code) => {
47
- process.exit(code || 0);
48
- });
49
-
50
- return;
51
- }
52
-
53
- console.error('❌ FRAIM MCP Server Error: Could not find server entry point.');
54
- console.error('Expected one of:');
55
- console.error(` - ${distPath}`);
56
- console.error(` - ${srcPath}`);
57
- process.exit(1);
58
- }
59
-
60
- // If this file is run directly, run the MCP server
61
- if (require.main === module) {
62
- runMCPServer();
63
- }